Merge "master" into "output". fc11-i386-build29 fc11-x64-build26 lenny-x64-build50 sid-i386-build98
authorBen Pfaff <blp@gnu.org>
Sat, 24 Oct 2009 15:42:33 +0000 (08:42 -0700)
committerBen Pfaff <blp@gnu.org>
Sat, 24 Oct 2009 15:42:33 +0000 (08:42 -0700)
18 files changed:
1  2 
INSTALL
NEWS
acinclude.m4
configure.ac
src/data/dictionary.c
src/language/command.c
src/language/data-io/print.c
src/language/dictionary/sys-file-info.c
src/language/stats/correlations.c
src/language/stats/descriptives.c
src/language/stats/examine.q
src/language/stats/frequencies.q
src/language/stats/regression.q
src/language/stats/t-test.q
src/output/charts/plot-hist.c
src/ui/gui/automake.mk
src/ui/gui/psppire.c
src/ui/terminal/automake.mk

diff --combined INSTALL
index 686109e48702d59413f1862e1e360acc50cbc64c,4f1bc84cef9b3c3eda18fc9165cdbc0f5e61d5aa..0f4f5c9687567dfaa9c322407387f889ed7d19be
+++ b/INSTALL
@@@ -24,7 -24,7 +24,7 @@@ The following packages are required to 
        MinGW (http://www.mingw.org/) are known to work.
  
      * The GNU Scientific Library (http://www.gnu.org/software/gsl/),
-       version 1.6 or later, including libgslcblas included with GSL.
+       version 1.8 or later, including libgslcblas included with GSL.
  
      * Perl (http://www.perl.org/), version 5.005_03 or later.  Perl is
        required during build but not after installation.
        If you don't have a version already, you can install GNU
        libiconv (http://www.gnu.org/software/libiconv/).
  
 -The following package is required to enable PSPP's graphing features.
 -If you cannot arrange to install it, you must run `configure' with
 ---without-libplot.
 +The following packages are required to enable PSPP's graphing
 +features.  If you cannot arrange to install them, you must run
 +`configure' with --without-cairo.
  
 -    * libplot, from GNU plotutils
 -      (http://www.gnu.org/software/plotutils/).
 +    * Cairo (http://cairographics.org/), version 1.5 or later.
 +
 +    * Pango (http://www.pango.org/), version 1.22 or later.
  
  The following packages are required to enable PSPPIRE, the graphical
  user interface for PSPP.  If you cannot install them or do not wish to
@@@ -51,16 -50,16 +51,16 @@@ use the GUI, you must run `configure' w
  
      * GTK+ (http://www.gtk.org/), version 2.12.0 or later.
  
- Installing the following packages will allow your PSPP binary to read
- Gnumeric files.
      * pkg-config (http://pkg-config.freedesktop.org/wiki/).  Versions
        0.18 and 0.19 have a bug that will prevent library detection,
        but other versions should be fine.
  
-       To cross-compile PSPP, you will likely need to set the
-       PKG_CONFIG_LIBDIR environment variable to point to an
-       appropriate pkg-config for the cross-compilation environment.
+ To cross-compile PSPP, you will likely need to set the
+ PKG_CONFIG_LIBDIR environment variable to point to an
+ appropriate pkg-config for the cross-compilation environment.
+ Installing the following packages will allow your PSPP binary to read
+ Gnumeric files.
  
      * zlib (http://www.zlib.net/).
  
@@@ -210,17 -209,14 +210,17 @@@ suffix on their names by giving `config
  Optional Features
  =================
  
 -`--without-libplot'
 -    Don't compile in support for charts (using libplot).  This is
 -    useful if your system doesn't have the libplot library.
 +`--without-cairo'
 +    Don't compile in support for charts (using Cairo and Pango).  This
 +    is useful if your system lacks these libraries.
  
  `--without-gui'
      Don't build the PSPPIRE gui.  Use this option if you only want to
      build the command line version of PSPP.
  
 +    Cairo and Pango required to build the GUI, so --without-cairo
 +    implies --without-gui.
 +
  `--with-gui-tools'
      Build the gui developer tools.  There is no reason to use this
      option unless you're involved with the development of PSPP
diff --combined NEWS
index 7f6c2a0e3463f5678a4b544989eee10d78a03c16,1aac688c8736a3b66322cf993fbc0f195ee9920f..5f952324f12229c7e3a110dfd688f7b0fa5e9c26
--- 1/NEWS
--- 2/NEWS
+++ b/NEWS
@@@ -1,17 -1,10 +1,17 @@@
  PSPP NEWS -- history of user-visible changes.
- Time-stamp: <2009-07-29 20:52:41 blp>
 -Time-stamp: <2009-09-08 21:08:29 blp>
++Time-stamp: <2009-10-24 08:12:04 blp>
  Copyright (C) 1996-9, 2000, 2008, 2009 Free Software Foundation, Inc.
  See the end for copying conditions.
  
  Please send PSPP bug reports to bug-gnu-pspp@gnu.org.
  
 +Changes from 0.7.2 to 0.7.3:
 +
 + * Charts are now produced with Cairo and Pango, instead of libplot.
 +   Without them, the new graphing features will not work.  If you do
 +   not have Cairo and Pango installed, you must run `configure' with
 +   --without-cairo.
 +
  Changes from 0.7.1 to 0.7.2:
  
   * Updated Perl module interface.
@@@ -25,7 -18,7 +25,7 @@@ Changes from 0.7.0 to 0.7.1
   *  Added a perl module to facilitate reading and writing of pspp system 
      files from perl programs.
  
- Changes from 0.6.1 to 0.7.0:
+ Changes from 0.6.2-pre6 to 0.7.0:
  
    * Custom variable and data file attributes are now supported.
      Commands VARIABLE ATTRIBUTE and DATAFILE ATTRIBUTE have been added
      been added to commands that read and write system files, such as
      SAVE and GET, as well as to the DISPLAY command.
  
+   * Numererous improvements to the Graphical User Interface have
+     made.  Notable improvements include:
+     - Non-Ascii characters in strings, labels and variable names are
+       now supported.
+     - A "Split Window" function is available, which makes it easier to
+       see different parts of a large data file.
+     - Data files can now be opened by specifing their name as the first
+       argument.  This means that on a properly configured desktop, double
+       clicking on an icon will open the file.
+     
+   * New statistical procedures:
+     - CORRELATIONS
+     - ROC
+     - RELIABILITY
+     NPAR TESTS now supports the WILCOXON and SIGN subcommands.
+     The CROSSTABS command has been completely re-implemented to fix numerous bugs.
+   * Three new commands to combine data files have been added: MATCH FILES,
+    UPDATE and  ADD FILES.
+   * A tutorial chapter has been added to the user manual.
+ Changes from 0.6.1 to 0.6.2-pre6:
+   * New translations:
+     - Dutch, thanks to Harry Thijssen.
+     - Brazilian Portuguese, thanks to Michel Boaventura.
+     Thanks for translations are also due to the coordinators at
+     translationproject.org.
+   * Statistical bug fixes:
+     - REGRESSION: Report correct standard error of the estimate (bug
+       #25677).
+     - T-TEST: Report correct significance of paired sample T-test in
+       the common case (bug #26936) and corner cases.  Thanks to Mike
+       Griffiths and Matej Cepl for reporting these bugs.
+   * Build fixes and changes:
+     - Make running "make" after running "configure" with different
+       settings reliably rebuild version.c.
+     - Cygwin and MinGW build fixes.
+     - Fixes for building with recent gnulib.
+     - The Makefile now honors two new variables, PSPP_LDFLAGS and
+       PSPPIRE_LDFLAGS, that affect linking of the PSPP and PSPPIRE
+       binaries, respectively.  This makes building easier for some
+       packagers.
+     - Fixes for "configure --enable-relocatable" (bug #25508).
+   * Data file bug fixes and changes:
+     - Fix reading text data files that contain a mix of white space
+       and commas.  Now "a ,b" is treated as two fields containing "a"
+       and "b"; previously it was treated as three, with an empty field
+       in the middle.
+     - Fix writing corrupted .sav files on Windows.
+     - Fix writing corrupted .por files (bug #26034).
+     - Fix reading .por files whose initial lines are not padded out
+       with spaces as expected.
+     - PSPP will no longer issue warnings about some .sav file records
+       or values that it does not understand.  These warnings were
+       harmless, but needlessly alarmed some users.
+     - Fix crash reading empty string fields from PostgreSQL databases.
+   * Bug fixes that affect PSPP and PSPPIRE:
+     - Users may now control precision of output statistics.  Instead
+       of hard coding the width and decimals of output numbers, respect
+       the default format in most instances.  Counts are now normally
+       displayed with the format of the weight variable, if any.
+     - Fix crash when an INSERT command specifies the name of a file
+       that does not exist (bug #24569).
+     - Fix crash when CROSSTABS specifies a long-string variable (bugs
+       #24557 and #26131).
+     - Fix crash drawing pie charts with many segments.
+     - Fix crash when NUMERIC specifies an invalid format.
+   * PSPPIRE bug fixes and changes:
+     - On Windows, write the output file to the user's home directory
+       instead of the current directory, to better match user
+       expectations.
+     - Some data editor fixes.
+   * Documentation:
+     - Fix typo in BINOMIAL section of user manual (bug #25892).
  Changes from 0.6.0 to 0.6.1:
  
    * Statistical bug fixes:
@@@ -673,8 -780,6 +787,6 @@@ Changes for version 0.1.0
  ----------------------------------------------------------------------
  Copyright information:
  
- Copyright (C) 1996-9, 2000 Free Software Foundation, Inc.
     Permission is granted to anyone to make or distribute verbatim
     copies of this document as received, in any medium, provided that
     the copyright notice and this permission notice are preserved, thus
diff --combined acinclude.m4
index 6141edd26782b69aa759919489cce281b44e16d3,307ce149a4344f3f5e373146cac3fefea7b5a08c..14d11dc70a26e44bc22f28bac8ca5418360c4843
@@@ -34,8 -34,49 +34,15 @@@ AC_DEFUN([PSPP_PERL]
    if test "$PERL" != no && $PERL -e 'require 5.005_03;'; then :; else
      PSPP_REQUIRED_PREREQ([Perl 5.005_03 (or later)])
    fi
+   # The PSPP autobuilder appends a build number to the PSPP version number,
+   # e.g. "0.7.2-build40".  But Perl won't parse version numbers that contain
+   # anything other than digits and periods, so "-build" causes an error.  So we
+   # define $(VERSION_FOR_PERL) that drops everything from the hyphen onward.
+   VERSION_FOR_PERL=`echo "$VERSION" | sed 's/-.*//'`
+   AC_SUBST([VERSION_FOR_PERL])
  ])
  
 -dnl Check that libplot is available.
 -AC_DEFUN([PSPP_LIBPLOT],
 -[
 -  AC_ARG_WITH(
 -    libplot, 
 -    [AS_HELP_STRING([--without-libplot],
 -                    [don't compile in support of charts (using libplot)])])
 -
 -  if test x"$with_libplot" != x"no" ; then 
 -    # Check whether we can link against libplot without any extra libraries.
 -    AC_CHECK_LIB(plot, pl_newpl_r, [LIBPLOT_LIBS="-lplot"])
 -
 -    # Check whether we can link against libplot if we also link X.
 -    if test x"$LIBPLOT_LIBS" = x""; then
 -      AC_PATH_XTRA
 -      extra_libs="-lXaw -lXmu -lXt $X_PRE_LIBS -lXext -lX11 $X_EXTRA_LIBS -lm"
 -      AC_CHECK_LIB(plot, pl_newpl_r,
 -                         [LIBPLOT_LIBS="-lplot $extra_libs"
 -                    LDFLAGS="$LDFLAGS $X_LIBS"],,
 -                         [$extra_libs])
 -    fi
 -
 -    # Still can't link?
 -    if test x"$LIBPLOT_LIBS" = x""; then
 -      PSPP_REQUIRED_PREREQ([libplot (or use --without-libplot)])
 -    fi
 -
 -    # Set up to make everything work.
 -    LIBS="$LIBPLOT_LIBS $LIBS"
 -    AC_DEFINE(HAVE_LIBPLOT, 1,
 -              [Define to 1 if you have the `libplot' library (-lplot).])
 -  fi
 -])
 -
  dnl PSPP_CHECK_CC_OPTION([OPTION], [ACTION-IF-ACCEPTED], [ACTION-IF-REJECTED])
  dnl Check whether the given C compiler OPTION is accepted.
  dnl If so, execute ACTION-IF-ACCEPTED, otherwise ACTION-IF-REJECTED.
@@@ -248,4 -289,26 +255,26 @@@ AC_DEFUN([PSPP_GSL_NEEDS_FGNU89_INLINE]
         CFLAGS="$CFLAGS -fgnu89-inline"
       fi])
  ])
- dnl acinclude.m4 ends here
+ AC_DEFUN([PSPP_CHECK_CLICKSEQUENCE],
+   [AC_REQUIRE([AM_INIT_AUTOMAKE])  # Defines MAKEINFO
+    AC_CACHE_CHECK([whether makeinfo supports @clicksequence],
+      [pspp_cv_have_clicksequence],
+      [cat > conftest.texi  <<EOF
+ @setfilename conftest.info
+ @clicksequence{File @click{} Open}
+ EOF
+       echo "configure:__oline__: running $MAKEINFO conftest.texi >&AS_MESSAGE_LOG_FD" >&AS_MESSAGE_LOG_FD
+       eval "$MAKEINFO conftest.texi >&AS_MESSAGE_LOG_FD 2>&1"
+       retval=$?
+       echo "configure:__oline__: \$? = $retval" >&AS_MESSAGE_LOG_FD
+       if test $retval = 0; then
+       pspp_cv_have_clicksequence=yes
+       else
+       pspp_cv_have_clicksequence=no
+       fi
+       rm -f conftest.texi conftest.info])
+    if test $pspp_cv_have_clicksequence = no; then
+        AM_MAKEINFOFLAGS="$AM_MAKEINFOFLAGS -DMISSING_CLICKSEQUENCE"
+        AC_SUBST([AM_MAKEINFOFLAGS])
+    fi])
diff --combined configure.ac
index c94935391c9a43a593d6b229aeb9996eaa1560e9,95dfc66f454604b1ee3c0a8d084511675a1860c5..499128b3c5e524aa46f2abb650cf5c43f4b642f4
@@@ -2,7 -2,7 +2,7 @@@ dnl Process this file with autoconf to 
  
  dnl Initialize.
  AC_PREREQ(2.60)
 -AC_INIT([pspp],[0.7.2],[bug-gnu-pspp@gnu.org])
 +AC_INIT([pspp],[0.7.3],[bug-gnu-pspp@gnu.org])
  AC_CONFIG_HEADERS([config.h])
  AM_INIT_AUTOMAKE
  
@@@ -16,6 -16,7 +16,7 @@@ AC_LIBTOOL_DLOPE
  AC_PROG_LIBTOOL
  PKG_PROG_PKG_CONFIG
  m4_pattern_forbid([PKG_CHECK_MODULES])
+ PSPP_CHECK_CLICKSEQUENCE
  
  AC_ARG_ENABLE(
    anachronistic-dependencies, 
@@@ -30,45 -31,36 +31,48 @@@ PSPP_CC_FOR_BUIL
  PSPP_PERL
  
  dnl Internationalization macros.
- AM_GNU_GETTEXT([external], [need-ngettext])
- AM_GNU_GETTEXT_VERSION([0.17])
+ AC_ARG_ENABLE(nls, [AS_HELP_STRING([--disable-nls], [do not use Native Language Support])])
+ if  test x"$enable_nls" != x"no"  ; then
+  AC_DEFINE(ENABLE_NLS, 1, [Define to 1 if translation of program messages to the user's native language is requested.])
+ fi
  
  dnl Checks for libraries.
  AC_SYS_LARGEFILE
  AC_SEARCH_LIBS([sin], [m])
 -PSPP_LIBPLOT
  PSPP_LC_PAPER
 -AM_CONDITIONAL(WITHCHARTS, test x"$with_libplot" != x"no")
  
  
  AC_ARG_VAR([PSPP_LDFLAGS], [linker flags to be used for linking the pspp binary only])
  AC_ARG_VAR([PSPPIRE_LDFLAGS], [linker flags to be used for linking the psppire binary only])
  
 -
 -AC_ARG_WITH(
 -  gui, 
 -  [AS_HELP_STRING([--without-gui], [don't build the PSPPIRE gui])])
 -
 -required_gtk_version=2.12
 -
 -if test x"$with_gui" != x"no" ; then 
 -  PKG_CHECK_MODULES(GTK, gtk+-2.0 >= $required_gtk_version,,
 -    [PSPP_REQUIRED_PREREQ([gtk+ 2.0 v$required_gtk_version or later (or use --without-gui)])])
 +# Support for Cairo and Pango.
 +AC_ARG_WITH([cairo],
 +  [AS_HELP_STRING(
 +    [--without-cairo], 
 +    [Don't build support for charts (using Cairo and Pango);
 +     implies --without-gui])],
 +  [], [with_cairo=yes])
 +AM_CONDITIONAL([HAVE_CAIRO], [test "$with_cairo" != no])
 +if test "$with_cairo" != no; then
 +  PKG_CHECK_MODULES([CAIRO], [cairo >= 1.5 pango >= 1.20 pangocairo], 
 +    [CPPFLAGS="$CPPFLAGS $CAIRO_CFLAGS"
 +     AC_DEFINE([HAVE_CAIRO], 1, 
 +       [Define to 1 if Cairo and Pango are available.])],
 +    [PSPP_REQUIRED_PREREQ([cairo 1.5 or later and pango 1.20 or later (or use --without-cairo)])])
  fi
 -AM_CONDITIONAL(WITHGUI, test x"$with_gui" != x"no")
  
 +# Support for GUI.
 +AC_ARG_WITH([gui], 
 +  [AS_HELP_STRING([--without-gui], 
 +                  [Don't build the PSPPIRE GUI (using GTK+)])],
 +  [], [with_gui=yes])
 +AM_CONDITIONAL([HAVE_GUI], 
 +               [test "$with_cairo" != no && test "$with_gui" != "no"])
 +if test "$with_cairo" != no && test "$with_gui" != "no"; then
 +  PKG_CHECK_MODULES([GTK], [gtk+-2.0 >= 2.12], [],
 +    [PSPP_REQUIRED_PREREQ([gtk+ 2.0 version 2.12 or later (or use --without-gui)])])
 +fi
  
  dnl Checks needed for psql reader
  
@@@ -214,9 -206,14 +218,14 @@@ if test "$am_cv_func_iconv" != "yes"; t
     PSPP_REQUIRED_PREREQ([iconv (see http://www.gnu.org/software/libiconv/)])
  fi
  
+ dnl Required by the gnulib 'relocatable-prog' module.
+ dnl See doc/relocatable-maint.texi in the gnulib tree for details.
+ RELOCATABLE_LIBRARY_PATH='$(libdir)'
+ RELOCATABLE_STRIP=:
  PSPP_CHECK_PREREQS
  
- AC_CONFIG_FILES([Makefile gl/Makefile po/Makefile.in])
+ AC_CONFIG_FILES([Makefile gl/Makefile])
  
  AC_OUTPUT
  echo "PSPP configured successfully."
diff --combined src/data/dictionary.c
index 7379d1940ad9b511bcffa03faf301aa0f7727238,ab653d874193a46d1f9a83a03f1e15ac4e09e7a6..1ddf5575aa68c4877f77fea845d3b4e6ea567ccc
@@@ -119,7 -119,7 +119,7 @@@ dict_dump (const struct dictionary *d
      {
        const struct variable *v =
        d->var[i];
-       printf ("Name: %s;\tdict_idx: %d; case_idx: %d\n",
+       printf ("Name: %s;\tdict_idx: %zu; case_idx: %zu\n",
              var_get_name (v),
              var_get_dict_index (v),
              var_get_case_index (v));
@@@ -1016,7 -1016,7 +1016,7 @@@ dict_set_case_limit (struct dictionary 
  const struct caseproto *
  dict_get_proto (const struct dictionary *d_)
  {
 -  struct dictionary *d = (struct dictionary *) d_;
 +  struct dictionary *d = CONST_CAST (struct dictionary *, d_);
    if (d->proto == NULL)
      {
        size_t i;
@@@ -1375,7 -1375,7 +1375,7 @@@ dict_clear_vectors (struct dictionary *
  struct attrset *
  dict_get_attributes (const struct dictionary *d) 
  {
 -  return (struct attrset *) &d->attributes;
 +  return CONST_CAST (struct attrset *, &d->attributes);
  }
  
  /* Replaces D's attributes set by a copy of ATTRS. */
diff --combined src/language/command.c
index 74f99a89a682009dfa0fa62452669cf8622a446c,32dba0b4f7cd0ca7760f18315e13ae0b845069a0..4c3612fb290977674247b7bd2d66801afa56f818
@@@ -37,6 -37,7 +37,6 @@@
  #include <libpspp/message.h>
  #include <libpspp/str.h>
  #include <output/manager.h>
 -#include <output/table.h>
  #include <libpspp/getl.h>
  
  #if HAVE_SYS_WAIT_H
@@@ -230,9 -231,9 +230,9 @@@ do_parse_command (struct lexer *lexer
  
    /* Execute command. */
    msg_set_command_name (command->name);
 -  tab_set_command_name (command->name);
 +  som_set_command_name (command->name);
    result = command->function (lexer, ds);
 -  tab_set_command_name (NULL);
 +  som_set_command_name (NULL);
    msg_set_command_name (NULL);
  
    assert (cmd_result_is_valid (result));
@@@ -688,9 -689,9 +688,9 @@@ report_state_mismatch (const struct com
          }
      }
    else if (state == CMD_STATE_INPUT_PROGRAM)
-     msg (SE, _("%s is not allowed inside INPUT PROGRAM."), command->name);
+     msg (SE, _("%s is not allowed inside %s."), command->name, "INPUT PROGRAM" );
    else if (state == CMD_STATE_FILE_TYPE)
-     msg (SE, _("%s is not allowed inside FILE TYPE."), command->name);
+     msg (SE, _("%s is not allowed inside %s."), command->name, "FILE TYPE");
  
    return false;
  }
index dd1e26d270dab5d8d13eff9a85146260b68cc053,2cfa0177c77950f26495aa9a5bd421ab8df73488..9c8f56e84289196182fc10bb8599e26a35c8f3b3
@@@ -396,8 -396,8 +396,8 @@@ dump_table (struct print_trns *trns, co
    int row;
  
    spec_cnt = ll_count (&trns->specs);
 -  t = tab_create (4, spec_cnt + 1, 0);
 -  tab_columns (t, TAB_COL_DOWN, 1);
 +  t = tab_create (4, spec_cnt + 1);
 +  tab_columns (t, TAB_COL_DOWN);
    tab_box (t, TAL_1, TAL_1, TAL_0, TAL_1, 0, 0, 3, spec_cnt);
    tab_hline (t, TAL_2, 0, 3, 1);
    tab_headers (t, 0, 0, 1, 0);
    tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("Record"));
    tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Columns"));
    tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Format"));
 -  tab_dim (t, tab_natural_dimensions, NULL);
 +  tab_dim (t, tab_natural_dimensions, NULL, NULL);
    row = 1;
    ll_for_each (spec, struct prt_out_spec, ll, &trns->specs)
      {
      }
  
    if (fh != NULL)
-     tab_title (t, ngettext ("Writing %d record to %s.",
-                             "Writing %d records to %s.", trns->record_cnt),
+     tab_title (t, ngettext ("Writing %zu record to %s.",
+                             "Writing %zu records to %s.", trns->record_cnt),
                 trns->record_cnt, fh_get_name (fh));
    else
-     tab_title (t, ngettext ("Writing %d record.",
-                             "Writing %d records.", trns->record_cnt),
+     tab_title (t, ngettext ("Writing %zu record.",
+                             "Writing %zu records.", trns->record_cnt),
                 trns->record_cnt);
    tab_submit (t);
  }
index 1202045d098cc6fdcd4bc342e6c610b5b01f0137,f68a830b83810ba6eec7d4e73b42ab40b041ca91..6c44a0c3baaefefbda7129b081442468106d7c9c
@@@ -69,18 -69,17 +69,18 @@@ static int describe_variable (const str
  /* Sets the widths of all the columns and heights of all the rows in
     table T for driver D. */
  static void
 -sysfile_info_dim (struct tab_table *t, struct outp_driver *d, void *aux UNUSED)
 +sysfile_info_dim (struct tab_rendering *r, void *aux UNUSED)
  {
 +  const struct tab_table *t = r->table;
    static const int max[] = {20, 5, 35, 3, 0};
    const int *p;
    int i;
  
    for (p = max; *p; p++)
 -    t->w[p - max] = MIN (tab_natural_width (t, d, p - max),
 -                       *p * d->prop_em_width);
 -  for (i = 0; i < t->nr; i++)
 -    t->h[i] = tab_natural_height (t, d, i);
 +    r->w[p - max] = MIN (tab_natural_width (r, p - max),
 +                         *p * r->driver->prop_em_width);
 +  for (i = 0; i < tab_nr (t); i++)
 +    r->h[i] = tab_natural_height (r, i);
  }
  
  /* SYSFILE INFO utility. */
@@@ -109,7 -108,7 +109,7 @@@ cmd_sysfile_info (struct lexer *lexer, 
      }
    casereader_destroy (reader);
  
 -  t = tab_create (2, 11, 0);
 +  t = tab_create (2, 11);
    tab_vline (t, TAL_GAP, 1, 0, 8);
    tab_text (t, 0, 0, TAB_LEFT, _("File:"));
    tab_text (t, 1, 0, TAB_LEFT, fh_get_file_name (h));
                     info.creation_date, info.creation_time, info.product);
    tab_text (t, 0, 3, TAB_LEFT, _("Integer Format:"));
    tab_text (t, 1, 3, TAB_LEFT,
-             info.integer_format == INTEGER_MSB_FIRST ? _("Big Endian.")
-             : info.integer_format == INTEGER_LSB_FIRST ? _("Little Endian.")
-             : _("Unknown."));
+             info.integer_format == INTEGER_MSB_FIRST ? _("Big Endian")
+             : info.integer_format == INTEGER_LSB_FIRST ? _("Little Endian")
+             : _("Unknown"));
    tab_text (t, 0, 4, TAB_LEFT, _("Real Format:"));
    tab_text (t, 1, 4, TAB_LEFT,
              info.float_format == FLOAT_IEEE_DOUBLE_LE ? _("IEEE 754 LE.")
              : info.float_format == FLOAT_VAX_D ? _("VAX D.")
              : info.float_format == FLOAT_VAX_G ? _("VAX G.")
              : info.float_format == FLOAT_Z_LONG ? _("IBM 390 Hex Long.")
-             : _("Unknown."));
+             : _("Unknown"));
    tab_text (t, 0, 5, TAB_LEFT, _("Variables:"));
    tab_text_format (t, 1, 5, TAB_LEFT, "%zu", dict_get_var_cnt (d));
    tab_text (t, 0, 6, TAB_LEFT, _("Cases:"));
                     info.case_cnt == -1 ? _("Unknown") : "%ld",
                     (long int) info.case_cnt);
    tab_text (t, 0, 7, TAB_LEFT, _("Type:"));
-   tab_text (t, 1, 7, TAB_LEFT, _("System File."));
+   tab_text (t, 1, 7, TAB_LEFT, _("System File"));
    tab_text (t, 0, 8, TAB_LEFT, _("Weight:"));
    {
      struct variable *weight_var = dict_get_weight (d);
                     dict_get_encoding(d) ? dict_get_encoding(d) : _("Unknown"));
  
  
 -  tab_dim (t, tab_natural_dimensions, NULL);
 +  tab_dim (t, tab_natural_dimensions, NULL, NULL);
    tab_submit (t);
  
 -  t = tab_create (4, 1 + 2 * dict_get_var_cnt (d), 1);
 -  tab_dim (t, sysfile_info_dim, NULL);
 +  t = tab_create (4, 1 + 2 * dict_get_var_cnt (d));
 +  tab_dim (t, sysfile_info_dim, NULL, NULL);
    tab_headers (t, 0, 0, 1, 0);
    tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("Variable"));
    tab_joint_text (t, 1, 0, 2, 0, TAB_LEFT | TAT_TITLE, _("Description"));
@@@ -340,45 -339,44 +340,45 @@@ display_documents (const struct diction
      }
  }
  
 -static int _flags;
 +struct variables_dim_aux
 +  {
 +    int flags;
 +  };
  
  /* Sets the widths of all the columns and heights of all the rows in
     table T for driver D. */
  static void
 -variables_dim (struct tab_table *t, struct outp_driver *d, void *aux UNUSED)
 +variables_dim (struct tab_rendering *r, void *aux_)
  {
 -  int pc;
 -  int i;
 +  const struct outp_driver *d = r->driver;
 +  struct variables_dim_aux *aux = aux_;
  
 -  t->w[0] = tab_natural_width (t, d, 0);
 -  if (_flags & (DF_VALUE_LABELS | DF_VARIABLE_LABELS | DF_MISSING_VALUES
 -                | DF_AT_ATTRIBUTES | DF_ATTRIBUTES))
 +  tab_natural_dimensions (r, NULL);
 +  if (aux->flags & (DF_VALUE_LABELS | DF_VARIABLE_LABELS | DF_MISSING_VALUES
 +                    | DF_AT_ATTRIBUTES | DF_ATTRIBUTES))
      {
 -      t->w[1] = MAX (tab_natural_width (t, d, 1), d->prop_em_width * 5);
 -      t->w[2] = MAX (tab_natural_width (t, d, 2), d->prop_em_width * 35);
 -      pc = 3;
 +      r->w[1] = MAX (r->w[1], d->prop_em_width * 5);
 +      r->w[2] = MAX (r->w[2], d->prop_em_width * 35);
      }
 -  else
 -    pc = 1;
 -  if (_flags & DF_DICT_INDEX)
 -    t->w[pc] = tab_natural_width (t, d, pc);
 +}
  
 -  for (i = 0; i < t->nr; i++)
 -    t->h[i] = tab_natural_height (t, d, i);
 +static void
 +variables_dim_free (void *aux_)
 +{
 +  struct variables_dim_aux *aux = aux_;
 +  free (aux);
  }
  
  static void
  display_variables (const struct variable **vl, size_t n, int flags)
  {
    struct tab_table *t;
 +  struct variables_dim_aux *aux;
    int nc;                     /* Number of columns. */
    int pc;                     /* `Position column' */
    int r;                      /* Current row. */
    size_t i;
  
 -  _flags = flags;
 -
    /* One column for the name,
       two columns for general description,
       one column for dictionary index. */
    if (flags & DF_DICT_INDEX)
      nc++;
  
 -  t = tab_create (nc, n + 5, 1);
 +  t = tab_create (nc, n + 5);
    tab_headers (t, 0, 0, 1, 0);
    tab_hline (t, TAL_2, 0, nc - 1, 1);
    tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("Variable"));
                       ? _("Description") : _("Label")));
    if (flags & DF_DICT_INDEX)
      tab_text (t, pc, 0, TAB_LEFT | TAT_TITLE, _("Position"));
 -  tab_dim (t, variables_dim, NULL);
 +
 +  aux = xmalloc (sizeof *aux);
 +  aux->flags = flags;
 +  tab_dim (t, variables_dim, variables_dim_free, aux);
  
    r = 1;
    for (i = 0; i < n; i++)
    if (flags & ~DF_DICT_INDEX)
      tab_vline (t, TAL_1, nc - 1, 0, r - 1);
    tab_resize (t, -1, r);
 -  tab_columns (t, TAB_COL_DOWN, 1);
 +  tab_columns (t, TAB_COL_DOWN);
    tab_submit (t);
  }
  \f
@@@ -483,15 -478,15 +483,15 @@@ display_data_file_attributes (struct at
    if (!n_attrs)
      return;
  
 -  t = tab_create (2, n_attrs + 1, 0);
 +  t = tab_create (2, n_attrs + 1);
    tab_headers (t, 0, 0, 1, 0);
    tab_box (t, TAL_1, TAL_1, -1, TAL_1, 0, 0, tab_nc (t) - 1, tab_nr (t) - 1);
    tab_hline (t, TAL_2, 0, 1, 1); 
    tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("Attribute"));
    tab_text (t, 1, 0, TAB_LEFT | TAT_TITLE, _("Value"));
    display_attributes (t, set, flags, 0, 1);
 -  tab_columns (t, TAB_COL_DOWN, 1);
 -  tab_dim (t, tab_natural_dimensions, NULL);
 +  tab_columns (t, TAB_COL_DOWN);
 +  tab_dim (t, tab_natural_dimensions, NULL, NULL);
    tab_title (t, "Custom data file attributes.");
    tab_submit (t);
  }
@@@ -718,10 -713,10 +718,10 @@@ display_vectors (const struct dictionar
    if (sorted)
      qsort (vl, nvec, sizeof *vl, compare_vector_ptrs_by_name);
  
 -  t = tab_create (4, nrow + 1, 0);
 +  t = tab_create (4, nrow + 1);
    tab_headers (t, 0, 0, 1, 0);
 -  tab_columns (t, TAB_COL_DOWN, 1);
 -  tab_dim (t, tab_natural_dimensions, NULL);
 +  tab_columns (t, TAB_COL_DOWN);
 +  tab_dim (t, tab_natural_dimensions, NULL, NULL);
    tab_box (t, TAL_1, TAL_1, -1, -1, 0, 0, 3, nrow);
    tab_box (t, -1, -1, -1, TAL_1, 0, 0, 3, nrow);
    tab_hline (t, TAL_2, 0, 3, 1);
index 0000000000000000000000000000000000000000,e397dae53b2ff482bb0ea9b31cc4b2685ddd14dd..ad90ef409051f47d12d8fcc2e48f5280fadf75aa
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,542 +1,542 @@@
 -  struct tab_table *t = tab_create (nc, nr, 0);
+ /* 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 <libpspp/assertion.h>
+ #include <math/covariance.h>
+ #include <math/design-matrix.h>
+ #include <gsl/gsl_matrix.h>
+ #include <data/casegrouper.h>
+ #include <data/casereader.h>
+ #include <data/dictionary.h>
+ #include <data/procedure.h>
+ #include <data/variable.h>
+ #include <language/command.h>
+ #include <language/dictionary/split-file.h>
+ #include <language/lexer/lexer.h>
+ #include <language/lexer/variable-parser.h>
+ #include <output/manager.h>
+ #include <output/table.h>
+ #include <libpspp/message.h>
+ #include <data/format.h>
+ #include <math/moments.h>
+ #include <math.h>
+ #include "xalloc.h"
+ #include "minmax.h"
+ #include <libpspp/misc.h>
+ #include <gsl/gsl_cdf.h>
+ #include "gettext.h"
+ #define _(msgid) gettext (msgid)
+ #define N_(msgid) msgid
+ static double
+ significance_of_correlation (double rho, double w)
+ {
+   double t = w - 2;
+   t /= 1 - MIN (1, pow2 (rho));
+   t = sqrt (t);
+   t *= rho;
+   
+   if (t > 0)
+     return  gsl_cdf_tdist_Q (t, w - 2);
+   else
+     return  gsl_cdf_tdist_P (t, w - 2);
+ }
+ struct corr
+ {
+   size_t n_vars_total;
+   size_t n_vars1;
+   const struct variable **vars;
+ };
+ /* Handling of missing values. */
+ enum corr_missing_type
+   {
+     CORR_PAIRWISE,       /* Handle missing values on a per-variable-pair basis. */
+     CORR_LISTWISE        /* Discard entire case if any variable is missing. */
+   };
+ enum stats_opts
+   {
+     STATS_DESCRIPTIVES = 0x01,
+     STATS_XPROD = 0x02,
+     STATS_ALL = STATS_XPROD | STATS_DESCRIPTIVES
+   };
+ struct corr_opts
+ {
+   enum corr_missing_type missing_type;
+   enum mv_class exclude;      /* Classes of missing values to exclude. */
+   bool sig;   /* Flag significant values or not */
+   int tails;  /* Report significance with how many tails ? */
+   enum stats_opts statistics;
+   const struct variable *wv;  /* The weight variable (if any) */
+ };
+ static void
+ output_descriptives (const struct corr *corr, const gsl_matrix *means,
+                    const gsl_matrix *vars, const gsl_matrix *ns)
+ {
+   const int nr = corr->n_vars_total + 1;
+   const int nc = 4;
+   int c, r;
+   const int heading_columns = 1;
+   const int heading_rows = 1;
 -  tab_dim (t, tab_natural_dimensions, NULL);
++  struct tab_table *t = tab_create (nc, nr);
+   tab_title (t, _("Descriptive Statistics"));
 -  t = tab_create (nc, nr, 0);
++  tab_dim (t, tab_natural_dimensions, NULL, NULL);
+   tab_headers (t, heading_columns, 0, heading_rows, 0);
+   /* Outline the box */
+   tab_box (t,
+          TAL_2, TAL_2,
+          -1, -1,
+          0, 0,
+          nc - 1, nr - 1);
+   /* Vertical lines */
+   tab_box (t,
+          -1, -1,
+          -1, TAL_1,
+          heading_columns, 0,
+          nc - 1, nr - 1);
+   tab_vline (t, TAL_2, heading_columns, 0, nr - 1);
+   tab_hline (t, TAL_1, 0, nc - 1, heading_rows);
+   tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("Mean"));
+   tab_text (t, 2, 0, TAB_CENTER | TAT_TITLE, _("Std. Deviation"));
+   tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("N"));
+   for (r = 0 ; r < corr->n_vars_total ; ++r)
+     {
+       const struct variable *v = corr->vars[r];
+       tab_text (t, 0, r + heading_rows, TAB_LEFT | TAT_TITLE, var_to_string (v));
+       for (c = 1 ; c < nc ; ++c)
+       {
+         double x ;
+         double n;
+         switch (c)
+           {
+           case 1:
+             x = gsl_matrix_get (means, r, 0);
+             break;
+           case 2:
+             x = gsl_matrix_get (vars, r, 0);
+             /* Here we want to display the non-biased estimator */
+             n = gsl_matrix_get (ns, r, 0);
+             x *= n / (n -1);
+             x = sqrt (x);
+             break;
+           case 3:
+             x = gsl_matrix_get (ns, r, 0);
+             break;
+           default: 
+             NOT_REACHED ();
+           };
+         
+         tab_double (t, c, r + heading_rows, 0, x, NULL);
+       }
+     }
+   tab_submit (t);
+ }
+ static void
+ output_correlation (const struct corr *corr, const struct corr_opts *opts,
+                   const gsl_matrix *cm, const gsl_matrix *samples,
+                   const gsl_matrix *cv)
+ {
+   int r, c;
+   struct tab_table *t;
+   int matrix_cols;
+   int nr = corr->n_vars1;
+   int nc = matrix_cols = corr->n_vars_total > corr->n_vars1 ?
+     corr->n_vars_total - corr->n_vars1 : corr->n_vars1;
+   const struct fmt_spec *wfmt = opts->wv ? var_get_print_format (opts->wv) : & F_8_0;
+   const int heading_columns = 2;
+   const int heading_rows = 1;
+   int rows_per_variable = opts->missing_type == CORR_LISTWISE ? 2 : 3;
+   if (opts->statistics & STATS_XPROD)
+     rows_per_variable += 2;
+   /* Two header columns */
+   nc += heading_columns;
+   /* Three data per variable */
+   nr *= rows_per_variable;
+   /* One header row */
+   nr += heading_rows;
 -  tab_dim (t, tab_natural_dimensions, NULL);
++  t = tab_create (nc, nr);
+   tab_title (t, _("Correlations"));
++  tab_dim (t, tab_natural_dimensions, NULL, NULL);
+   tab_headers (t, heading_columns, 0, heading_rows, 0);
+   /* Outline the box */
+   tab_box (t,
+          TAL_2, TAL_2,
+          -1, -1,
+          0, 0,
+          nc - 1, nr - 1);
+   /* Vertical lines */
+   tab_box (t,
+          -1, -1,
+          -1, TAL_1,
+          heading_columns, 0,
+          nc - 1, nr - 1);
+   tab_vline (t, TAL_2, heading_columns, 0, nr - 1);
+   tab_vline (t, TAL_1, 1, heading_rows, nr - 1);
+   for (r = 0 ; r < corr->n_vars1 ; ++r)
+     {
+       tab_text (t, 0, 1 + r * rows_per_variable, TAB_LEFT | TAT_TITLE, 
+               var_to_string (corr->vars[r]));
+       tab_text (t, 1, 1 + r * rows_per_variable, TAB_LEFT | TAT_TITLE, _("Pearson Correlation"));
+       tab_text (t, 1, 2 + r * rows_per_variable, TAB_LEFT | TAT_TITLE, 
+               (opts->tails == 2) ? _("Sig. (2-tailed)") : _("Sig. (1-tailed)"));
+       if (opts->statistics & STATS_XPROD)
+       {
+         tab_text (t, 1, 3 + r * rows_per_variable, TAB_LEFT | TAT_TITLE, _("Cross-products"));
+         tab_text (t, 1, 4 + r * rows_per_variable, TAB_LEFT | TAT_TITLE, _("Covariance"));
+       }
+       if ( opts->missing_type != CORR_LISTWISE )
+       tab_text (t, 1, rows_per_variable + r * rows_per_variable, TAB_LEFT | TAT_TITLE, _("N"));
+       tab_hline (t, TAL_1, 0, nc - 1, r * rows_per_variable + 1);
+     }
+   for (c = 0 ; c < matrix_cols ; ++c)
+     {
+       const struct variable *v = corr->n_vars_total > corr->n_vars1 ? corr->vars[corr->n_vars_total - corr->n_vars1 + c] : corr->vars[c];
+       tab_text (t, heading_columns + c, 0, TAB_LEFT | TAT_TITLE, var_to_string (v));      
+     }
+   for (r = 0 ; r < corr->n_vars1 ; ++r)
+     {
+       const int row = r * rows_per_variable + heading_rows;
+       for (c = 0 ; c < matrix_cols ; ++c)
+       {
+         unsigned char flags = 0; 
+         const int col_index = corr->n_vars_total - corr->n_vars1 + c;
+         double pearson = gsl_matrix_get (cm, r, col_index);
+         double w = gsl_matrix_get (samples, r, col_index);
+         double sig = opts->tails * significance_of_correlation (pearson, w);
+         if ( opts->missing_type != CORR_LISTWISE )
+           tab_double (t, c + heading_columns, row + rows_per_variable - 1, 0, w, wfmt);
+         if ( c != r)
+           tab_double (t, c + heading_columns, row + 1, 0,  sig, NULL);
+         if ( opts->sig && c != r && sig < 0.05)
+           flags = TAB_EMPH;
+         
+         tab_double (t, c + heading_columns, row, flags, pearson, NULL);
+         if (opts->statistics & STATS_XPROD)
+           {
+             double cov = gsl_matrix_get (cv, r, col_index);
+             const double xprod_dev = cov * w;
+             cov *= w / (w - 1.0);
+             tab_double (t, c + heading_columns, row + 2, 0, xprod_dev, NULL);
+             tab_double (t, c + heading_columns, row + 3, 0, cov, NULL);
+           }
+       }
+     }
+   tab_submit (t);
+ }
+ static gsl_matrix *
+ correlation_from_covariance (const gsl_matrix *cv, const gsl_matrix *v)
+ {
+   size_t i, j;
+   gsl_matrix *corr = gsl_matrix_calloc (cv->size1, cv->size2);
+   
+   for (i = 0 ; i < cv->size1; ++i)
+     {
+       for (j = 0 ; j < cv->size2; ++j)
+       {
+         double rho = gsl_matrix_get (cv, i, j);
+         
+         rho /= sqrt (gsl_matrix_get (v, i, j))
+           * 
+           sqrt (gsl_matrix_get (v, j, i));
+         
+         gsl_matrix_set (corr, i, j, rho);
+       }
+     }
+   
+   return corr;
+ }
+ static void
+ run_corr (struct casereader *r, const struct corr_opts *opts, const struct corr *corr)
+ {
+   struct ccase *c;
+   const gsl_matrix *var_matrix,  *samples_matrix, *mean_matrix;
+   const gsl_matrix *cov_matrix;
+   gsl_matrix *corr_matrix;
+   struct covariance *cov = covariance_create (corr->n_vars_total, corr->vars,
+                                             opts->wv, opts->exclude);
+   for ( ; (c = casereader_read (r) ); case_unref (c))
+     {
+       covariance_accumulate (cov, c);
+     }
+   cov_matrix = covariance_calculate (cov);
+   samples_matrix = covariance_moments (cov, MOMENT_NONE);
+   var_matrix = covariance_moments (cov, MOMENT_VARIANCE);
+   mean_matrix = covariance_moments (cov, MOMENT_MEAN);
+   corr_matrix = correlation_from_covariance (cov_matrix, var_matrix);
+   if ( opts->statistics & STATS_DESCRIPTIVES) 
+     output_descriptives (corr, mean_matrix, var_matrix, samples_matrix);
+   output_correlation (corr, opts,
+                     corr_matrix,
+                     samples_matrix,
+                     cov_matrix);
+   covariance_destroy (cov);
+   gsl_matrix_free (corr_matrix);
+ }
+ int
+ cmd_correlation (struct lexer *lexer, struct dataset *ds)
+ {
+   int i;
+   int n_all_vars = 0; /* Total number of variables involved in this command */
+   const struct variable **all_vars ;
+   const struct dictionary *dict = dataset_dict (ds);
+   bool ok = true;
+   struct casegrouper *grouper;
+   struct casereader *group;
+   struct corr *corr = NULL;
+   size_t n_corrs = 0;
+   struct corr_opts opts;
+   opts.missing_type = CORR_PAIRWISE;
+   opts.wv = dict_get_weight (dict);
+   opts.tails = 2;
+   opts.sig = false;
+   opts.exclude = MV_ANY;
+   opts.statistics = 0;
+   /* Parse CORRELATIONS. */
+   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, "PAIRWISE"))
+                 opts.missing_type = CORR_PAIRWISE;
+               else if (lex_match_id (lexer, "LISTWISE"))
+                 opts.missing_type = CORR_LISTWISE;
+               else if (lex_match_id (lexer, "INCLUDE"))
+                 opts.exclude = MV_SYSTEM;
+               else if (lex_match_id (lexer, "EXCLUDE"))
+               opts.exclude = MV_ANY;
+               else
+                 {
+                   lex_error (lexer, NULL);
+                   goto error;
+                 }
+               lex_match (lexer, ',');
+             }
+         }
+       else if (lex_match_id (lexer, "PRINT"))
+       {
+           lex_match (lexer, '=');
+           while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+           {
+             if ( lex_match_id (lexer, "TWOTAIL"))
+               opts.tails = 2;
+             else if (lex_match_id (lexer, "ONETAIL"))
+               opts.tails = 1;
+             else if (lex_match_id (lexer, "SIG"))
+               opts.sig = false;
+             else if (lex_match_id (lexer, "NOSIG"))
+               opts.sig = true;
+             else
+               {
+                 lex_error (lexer, NULL);
+                 goto error;
+               }
+               lex_match (lexer, ',');
+           }
+       }
+       else if (lex_match_id (lexer, "STATISTICS"))
+       {
+         lex_match (lexer, '=');
+           while (lex_token (lexer) != '.' && lex_token (lexer) != '/')
+           {
+             if ( lex_match_id (lexer, "DESCRIPTIVES"))
+               opts.statistics = STATS_DESCRIPTIVES;
+             else if (lex_match_id (lexer, "XPROD"))
+               opts.statistics = STATS_XPROD;
+             else if (lex_token (lexer) == T_ALL)
+               {
+                 opts.statistics = STATS_ALL;
+                 lex_get (lexer);
+               }
+             else 
+               {
+                 lex_error (lexer, NULL);
+                 goto error;
+               }
+               lex_match (lexer, ',');
+           }
+       }
+       else
+       {
+         if (lex_match_id (lexer, "VARIABLES"))
+           {
+             lex_match (lexer, '=');
+           }
+         corr = xrealloc (corr, sizeof (*corr) * (n_corrs + 1));
+         corr[n_corrs].n_vars_total = corr[n_corrs].n_vars1 = 0;
+       
+         if ( ! parse_variables_const (lexer, dict, &corr[n_corrs].vars, 
+                                       &corr[n_corrs].n_vars_total,
+                                       PV_NUMERIC))
+           {
+             ok = false;
+             break;
+           }
+         corr[n_corrs].n_vars1 = corr[n_corrs].n_vars_total;
+         if ( lex_match (lexer, T_WITH))
+           {
+             if ( ! parse_variables_const (lexer, dict,
+                                           &corr[n_corrs].vars, &corr[n_corrs].n_vars_total,
+                                           PV_NUMERIC | PV_APPEND))
+               {
+                 ok = false;
+                 break;
+               }
+           }
+         n_all_vars += corr[n_corrs].n_vars_total;
+         n_corrs++;
+       }
+     }
+   if (n_corrs == 0)
+     {
+       msg (SE, _("No variables specified."));
+       goto error;
+     }
+   all_vars = xmalloc (sizeof (*all_vars) * n_all_vars);
+   {
+     /* FIXME:  Using a hash here would make more sense */
+     const struct variable **vv = all_vars;
+     for (i = 0 ; i < n_corrs; ++i)
+       {
+       int v;
+       const struct corr *c = &corr[i];
+       for (v = 0 ; v < c->n_vars_total; ++v)
+         *vv++ = c->vars[v];
+       }
+   }
+   grouper = casegrouper_create_splits (proc_open (ds), dict);
+   while (casegrouper_get_next_group (grouper, &group))
+     {
+       for (i = 0 ; i < n_corrs; ++i)
+       {
+         /* FIXME: No need to iterate the data multiple times */
+         struct casereader *r = casereader_clone (group);
+         if ( opts.missing_type == CORR_LISTWISE)
+           r = casereader_create_filter_missing (r, all_vars, n_all_vars,
+                                                 opts.exclude, NULL, NULL);
+         run_corr (r, &opts,  &corr[i]);
+         casereader_destroy (r);
+       }
+       casereader_destroy (group);
+     }
+   ok = casegrouper_destroy (grouper);
+   ok = proc_commit (ds) && ok;
+   free (all_vars);
+   /* Done. */
+   free (corr);
+   return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
+  error:
+   free (corr);
+   return CMD_FAILURE;
+ }
index d87410fb17a4a19226db63768e6f7baed99f22d6,6b57fd297d8475ad63bcecc320a8c0c1b2d9201f..e78d771e147a95ea5630360d8e9c120984f96a14
@@@ -100,13 -100,13 +100,13 @@@ struct dsc_statistic_inf
  static const struct dsc_statistic_info dsc_info[DSC_N_STATS] =
    {
      {"MEAN", N_("Mean"), MOMENT_MEAN},
-     {"SEMEAN", N_("S E Mean"), MOMENT_VARIANCE},
+     {"SEMEAN", N_("S.E. Mean"), MOMENT_VARIANCE},
      {"STDDEV", N_("Std Dev"), MOMENT_VARIANCE},
      {"VARIANCE", N_("Variance"), MOMENT_VARIANCE},
      {"KURTOSIS", N_("Kurtosis"), MOMENT_KURTOSIS},
-     {"SEKURTOSIS", N_("S E Kurt"), MOMENT_NONE},
+     {"SEKURTOSIS", N_("S.E. Kurt"), MOMENT_NONE},
      {"SKEWNESS", N_("Skewness"), MOMENT_SKEWNESS},
-     {"SESKEWNESS", N_("S E Skew"), MOMENT_NONE},
+     {"SESKEWNESS", N_("S.E. Skew"), MOMENT_NONE},
      {"RANGE", N_("Range"), MOMENT_NONE},
      {"MINIMUM", N_("Minimum"), MOMENT_NONE},
      {"MAXIMUM", N_("Maximum"), MOMENT_NONE},
@@@ -552,15 -552,15 +552,15 @@@ dump_z_table (struct dsc_proc *dsc
        cnt++;
    }
  
 -  t = tab_create (2, cnt + 1, 0);
 +  t = tab_create (2, cnt + 1);
    tab_title (t, _("Mapping of variables to corresponding Z-scores."));
 -  tab_columns (t, SOM_COL_DOWN, 1);
 +  tab_columns (t, SOM_COL_DOWN);
    tab_headers (t, 0, 0, 1, 0);
    tab_box (t, TAL_1, TAL_1, TAL_0, TAL_1, 0, 0, 1, cnt);
    tab_hline (t, TAL_2, 0, 1, 1);
    tab_text (t, 0, 0, TAB_CENTER | TAT_TITLE, _("Source"));
    tab_text (t, 1, 0, TAB_CENTER | TAT_TITLE, _("Target"));
 -  tab_dim (t, tab_natural_dimensions, NULL);
 +  tab_dim (t, tab_natural_dimensions, NULL, NULL);
  
    {
      size_t i, y;
@@@ -873,13 -873,13 +873,13 @@@ display (struct dsc_proc *dsc
      sort (dsc->vars, dsc->var_cnt, sizeof *dsc->vars,
            descriptives_compare_dsc_vars, dsc);
  
 -  t = tab_create (nc, dsc->var_cnt + 1, 0);
 +  t = tab_create (nc, dsc->var_cnt + 1);
    tab_headers (t, 1, 0, 1, 0);
    tab_box (t, TAL_1, TAL_1, -1, -1, 0, 0, nc - 1, dsc->var_cnt);
    tab_box (t, -1, -1, -1, TAL_1, 1, 0, nc - 1, dsc->var_cnt);
    tab_hline (t, TAL_2, 0, nc - 1, 1);
    tab_vline (t, TAL_2, 1, 0, dsc->var_cnt);
 -  tab_dim (t, tab_natural_dimensions, NULL);
 +  tab_dim (t, tab_natural_dimensions, NULL, NULL);
  
    nc = 0;
    tab_text (t, nc++, 0, TAB_LEFT | TAT_TITLE, _("Variable"));
index b56fad4c65bc432c93baf60b09c6c4663906bc50,08077942340234031939cded549e87886d5119ee..1d399b5a1888908a4b08c8cfe2874da0af039bed
@@@ -49,7 -49,7 +49,7 @@@
  #include <libpspp/str.h>
  #include <math/moments.h>
  #include <output/charts/box-whisker.h>
 -#include <output/charts/cartesian.h>
 +#include <output/charts/np-plot.h>
  #include <output/manager.h>
  #include <output/table.h>
  
@@@ -104,11 -104,11 +104,11 @@@ struct factor_metric
    struct percentile **ptl;
    size_t n_ptiles;
  
 -  struct statistic *tukey_hinges;
 -  struct statistic *box_whisker;
 -  struct statistic *trimmed_mean;
 -  struct statistic *histogram;
 -  struct order_stats *np;
 +  struct tukey_hinges *tukey_hinges;
 +  struct box_whisker *box_whisker;
 +  struct trimmed_mean *trimmed_mean;
 +  struct histogram *histogram;
 +  struct np *np;
  
    /* Three quartiles indexing into PTL */
    struct percentile **quartiles;
@@@ -179,12 -179,12 +179,12 @@@ factor_destroy (struct xfactor *fctr
          moments1_destroy (result->metrics[v].moments);
          extrema_destroy (result->metrics[v].minima);
          extrema_destroy (result->metrics[v].maxima);
 -        statistic_destroy (result->metrics[v].trimmed_mean);
 -        statistic_destroy (result->metrics[v].tukey_hinges);
 -        statistic_destroy (result->metrics[v].box_whisker);
 -        statistic_destroy (result->metrics[v].histogram);
 +        statistic_destroy (&result->metrics[v].trimmed_mean->parent.parent);
 +        statistic_destroy (&result->metrics[v].tukey_hinges->parent.parent);
 +        statistic_destroy (&result->metrics[v].box_whisker->parent.parent);
 +        statistic_destroy (&result->metrics[v].histogram->parent);
          for (i = 0 ; i < result->metrics[v].n_ptiles; ++i)
 -          statistic_destroy ((struct statistic *) result->metrics[v].ptl[i]);
 +          statistic_destroy (&result->metrics[v].ptl[i]->parent.parent);
          free (result->metrics[v].ptl);
          free (result->metrics[v].quartiles);
          casereader_destroy (result->metrics[v].up_reader);
@@@ -320,6 -320,82 +320,6 @@@ cmd_examine (struct lexer *lexer, struc
  };
  
  
 -/* Plot the normal and detrended normal plots for RESULT.
 -   Label the plots with LABEL */
 -static void
 -np_plot (struct np *np, const char *label)
 -{
 -  double yfirst = 0, ylast = 0;
 -
 -  double x_lower;
 -  double x_upper;
 -  double slack;
 -
 -  /* Normal Plot */
 -  struct chart *np_chart;
 -
 -  /* Detrended Normal Plot */
 -  struct chart *dnp_chart;
 -
 -  /* The slope and intercept of the ideal normal probability line */
 -  const double slope = 1.0 / np->stddev;
 -  const double intercept = -np->mean / np->stddev;
 -
 -  if ( np->n < 1.0 )
 -    {
 -      msg (MW, _("Not creating plot because data set is empty."));
 -      return ;
 -    }
 -
 -  np_chart = chart_create ();
 -  dnp_chart = chart_create ();
 -
 -  if ( !np_chart || ! dnp_chart )
 -    return ;
 -
 -  chart_write_title (np_chart, _("Normal Q-Q Plot of %s"), label);
 -  chart_write_xlabel (np_chart, _("Observed Value"));
 -  chart_write_ylabel (np_chart, _("Expected Normal"));
 -
 -  chart_write_title (dnp_chart, _("Detrended Normal Q-Q Plot of %s"),
 -                   label);
 -  chart_write_xlabel (dnp_chart, _("Observed Value"));
 -  chart_write_ylabel (dnp_chart, _("Dev from Normal"));
 -
 -  yfirst = gsl_cdf_ugaussian_Pinv (1 / (np->n + 1));
 -  ylast = gsl_cdf_ugaussian_Pinv (np->n / (np->n + 1));
 -
 -  /* Need to make sure that both the scatter plot and the ideal fit into the
 -     plot */
 -  x_lower = MIN (np->y_min, (yfirst - intercept) / slope) ;
 -  x_upper = MAX (np->y_max, (ylast  - intercept) / slope) ;
 -  slack = (x_upper - x_lower)  * 0.05 ;
 -
 -  chart_write_xscale (np_chart, x_lower - slack, x_upper + slack, 5);
 -  chart_write_xscale (dnp_chart, np->y_min, np->y_max, 5);
 -
 -  chart_write_yscale (np_chart, yfirst, ylast, 5);
 -  chart_write_yscale (dnp_chart, np->dns_min, np->dns_max, 5);
 -
 -  {
 -    struct casereader *reader = casewriter_make_reader (np->writer);
 -    struct ccase *c;
 -    while ((c = casereader_read (reader)) != NULL)
 -      {
 -              chart_datum (np_chart, 0, case_data_idx (c, NP_IDX_Y)->f, case_data_idx (c, NP_IDX_NS)->f);
 -      chart_datum (dnp_chart, 0, case_data_idx (c, NP_IDX_Y)->f, case_data_idx (c, NP_IDX_DNS)->f);
 -
 -      case_unref (c);
 -      }
 -    casereader_destroy (reader);
 -  }
 -
 -  chart_line (dnp_chart, 0, 0, np->y_min, np->y_max , CHART_DIM_X);
 -  chart_line (np_chart, slope, intercept, yfirst, ylast , CHART_DIM_Y);
 -
 -  chart_submit (np_chart);
 -  chart_submit (dnp_chart);
 -}
  
  
  static void
@@@ -336,37 -412,20 +336,37 @@@ show_npplot (const struct variable **de
           ll != ll_null (&fctr->result_list);
           ll = ll_next (ll))
        {
 -        struct string str;
 +        struct string label;
          const struct factor_result *result =
            ll_data (ll, struct factor_result, ll);
 -
 -        ds_init_empty (&str);
 -        ds_put_format (&str, "%s ", var_get_name (dependent_var[v]));
 -
 -        factor_to_string (fctr, result, &str);
 -
 -        np_plot ((struct np*) result->metrics[v].np, ds_cstr(&str));
 -
 -        statistic_destroy ((struct statistic *)result->metrics[v].np);
 -
 -        ds_destroy (&str);
 +          struct chart *npp, *dnpp;
 +          struct casereader *reader;
 +          struct np *np;
 +
 +        ds_init_empty (&label);
 +        ds_put_format (&label, "%s ", var_get_name (dependent_var[v]));
 +        factor_to_string (fctr, result, &label);
 +
 +          np = result->metrics[v].np;
 +          reader = casewriter_make_reader (np->writer);
 +          npp = np_plot_create (np, reader, ds_cstr (&label));
 +          dnpp = dnp_plot_create (np, reader, ds_cstr (&label));
 +
 +        ds_destroy (&label);
 +
 +          if (npp == NULL || dnpp == NULL)
 +            {
 +              msg (MW, _("Not creating NP plot because data set is empty."));
 +              chart_unref (npp);
 +              chart_unref (dnpp);
 +            }
 +          else
 +            {
 +              chart_submit (npp);
 +              chart_submit (dnpp);
 +            }
 +
 +        statistic_destroy (&np->parent.parent);
        }
      }
  }
@@@ -389,25 -448,15 +389,25 @@@ show_histogram (const struct variable *
          struct string str;
          const struct factor_result *result =
            ll_data (ll, struct factor_result, ll);
 +          struct histogram *histogram;
 +          double mean, var, n;
 +
 +          histogram = result->metrics[v].histogram;
 +          if (histogram == NULL)
 +            {
 +              /* Probably all values are SYSMIS. */
 +              continue;
 +            }
  
          ds_init_empty (&str);
          ds_put_format (&str, "%s ", var_get_name (dependent_var[v]));
  
          factor_to_string (fctr, result, &str);
  
 -        histogram_plot ((struct histogram *) result->metrics[v].histogram,
 -                        ds_cstr (&str),
 -                        (struct moments1 *) result->metrics[v].moments);
 +          moments1_calculate (result->metrics[v].moments,
 +                              &n, &mean, &var, NULL,  NULL);
 +          chart_submit (histogram_chart_create (histogram, ds_cstr (&str),
 +                                                n, mean, sqrt (var), false));
  
          ds_destroy (&str);
        }
@@@ -425,18 -474,25 +425,18 @@@ show_boxplot_groups (const struct varia
  
    for (v = 0; v < n_dep_var; ++v)
      {
 -      struct ll *ll;
 -      int f = 0;
 -      struct chart *ch = chart_create ();
 +      const struct factor_result *result;
 +      struct boxplot *boxplot;
        double y_min = DBL_MAX;
        double y_max = -DBL_MAX;
 +      char *title;
  
 -      for (ll = ll_head (&fctr->result_list);
 -         ll != ll_null (&fctr->result_list);
 -         ll = ll_next (ll))
 +      ll_for_each (result, struct factor_result, ll, &fctr->result_list)
        {
 +          struct factor_metrics *metrics = &result->metrics[v];
 +        const struct ll_list *max_list = extrema_list (metrics->maxima);
 +        const struct ll_list *min_list = extrema_list (metrics->minima);
          const struct extremum  *max, *min;
 -        const struct factor_result *result =
 -          ll_data (ll, struct factor_result, ll);
 -
 -        const struct ll_list *max_list =
 -          extrema_list (result->metrics[v].maxima);
 -
 -        const struct ll_list *min_list =
 -          extrema_list (result->metrics[v].minima);
  
          if ( ll_is_empty (max_list))
            {
              continue;
            }
  
 -        max = (const struct extremum *)
 -          ll_data (ll_head(max_list), struct extremum, ll);
 -
 -          min = (const struct extremum *)
 -          ll_data (ll_head (min_list), struct extremum, ll);
 +        max = ll_data (ll_head(max_list), struct extremum, ll);
 +          min = ll_data (ll_head (min_list), struct extremum, ll);
  
          y_max = MAX (y_max, max->value);
          y_min = MIN (y_min, min->value);
        }
  
 -      boxplot_draw_yscale (ch, y_max, y_min);
 -
 -      if ( fctr->indep_var[0])
 -      chart_write_title (ch, _("Boxplot of %s vs. %s"),
 +      if (fctr->indep_var[0])
 +      title = xasprintf (_("Boxplot of %s vs. %s"),
                           var_to_string (dependent_var[v]),
 -                         var_to_string (fctr->indep_var[0]) );
 +                         var_to_string (fctr->indep_var[0]));
        else
 -      chart_write_title (ch, _("Boxplot of %s"),
 -                         var_to_string (dependent_var[v]));
 +      title = xasprintf (_("Boxplot of %s"),
 +                           var_to_string (dependent_var[v]));
 +      boxplot = boxplot_create (y_min, y_max, title);
 +      free (title);
  
 -      for (ll = ll_head (&fctr->result_list);
 -         ll != ll_null (&fctr->result_list);
 -         ll = ll_next (ll))
 +      ll_for_each (result, struct factor_result, ll, &fctr->result_list)
        {
 -        const struct factor_result *result =
 -          ll_data (ll, struct factor_result, ll);
 -
 -        struct string str;
 -        const double box_width = (ch->data_right - ch->data_left)
 -          / (ll_count (&fctr->result_list) * 2.0 ) ;
 -
 -        const double box_centre = (f++ * 2 + 1) * box_width + ch->data_left;
 -
 -        ds_init_empty (&str);
 +          struct factor_metrics *metrics = &result->metrics[v];
 +        struct string str = DS_EMPTY_INITIALIZER;
          factor_to_string_concise (fctr, result, &str);
 -
 -        boxplot_draw_boxplot (ch,
 -                              box_centre, box_width,
 -                              (const struct box_whisker *)
 -                               result->metrics[v].box_whisker,
 -                              ds_cstr (&str));
 -
 +          boxplot_add_box (boxplot, metrics->box_whisker, ds_cstr (&str));
 +          metrics->box_whisker = NULL;
          ds_destroy (&str);
        }
  
 -      chart_submit (ch);
 +      chart_submit (boxplot_get_chart (boxplot));
      }
  }
  
@@@ -484,42 -558,74 +484,42 @@@ show_boxplot_variables (const struct va
                        )
  
  {
 +  const struct factor_result *result;
    int v;
 -  struct ll *ll;
 -  const struct ll_list *result_list = &fctr->result_list;
 -
 -  for (ll = ll_head (result_list);
 -       ll != ll_null (result_list);
 -       ll = ll_next (ll))
  
 +  ll_for_each (result, struct factor_result, ll, &fctr->result_list)
      {
        struct string title;
 -      struct chart *ch = chart_create ();
        double y_min = DBL_MAX;
        double y_max = -DBL_MAX;
 -
 -      const struct factor_result *result =
 -      ll_data (ll, struct factor_result, ll);
 -
 -      const double box_width = (ch->data_right - ch->data_left)
 -      / (n_dep_var * 2.0 ) ;
 +      struct boxplot *boxplot;
  
        for (v = 0; v < n_dep_var; ++v)
        {
 -        const struct ll *max_ll =
 -          ll_head (extrema_list (result->metrics[v].maxima));
 -        const struct ll *min_ll =
 -          ll_head (extrema_list (result->metrics[v].minima));
 -
 -        const struct extremum  *max =
 -          (const struct extremum *) ll_data (max_ll, struct extremum, ll);
 -
 -          const struct extremum  *min =
 -          (const struct extremum *) ll_data (min_ll, struct extremum, ll);
 +          const struct factor_metrics *metrics = &result->metrics[v];
 +        const struct ll *max_ll = ll_head (extrema_list (metrics->maxima));
 +        const struct ll *min_ll = ll_head (extrema_list (metrics->minima));
 +        const struct extremum *max = ll_data (max_ll, struct extremum, ll);
 +          const struct extremum *min = ll_data (min_ll, struct extremum, ll);
  
          y_max = MAX (y_max, max->value);
          y_min = MIN (y_min, min->value);
        }
  
 -
 -      boxplot_draw_yscale (ch, y_max, y_min);
 -
        ds_init_empty (&title);
        factor_to_string (fctr, result, &title);
 -
 -#if 0
 -      ds_put_format (&title, "%s = ", var_get_name (fctr->indep_var[0]));
 -      var_append_value_name (fctr->indep_var[0], &result->value[0], &title);
 -#endif
 -
 -      chart_write_title (ch, ds_cstr (&title));
 +      boxplot = boxplot_create (y_min, y_max, ds_cstr (&title));
        ds_destroy (&title);
  
        for (v = 0; v < n_dep_var; ++v)
        {
 -        struct string str;
 -        const double box_centre = (v * 2 + 1) * box_width + ch->data_left;
 -
 -        ds_init_empty (&str);
 -        ds_init_cstr (&str, var_get_name (dependent_var[v]));
 -
 -        boxplot_draw_boxplot (ch,
 -                              box_centre, box_width,
 -                              (const struct box_whisker *) result->metrics[v].box_whisker,
 -                              ds_cstr (&str));
 -
 -        ds_destroy (&str);
 +          struct factor_metrics *metrics = &result->metrics[v];
 +          boxplot_add_box (boxplot, metrics->box_whisker,
 +                           var_get_name (dependent_var[v]));
 +          metrics->box_whisker = NULL;
        }
  
 -      chart_submit (ch);
 +      chart_submit (boxplot_get_chart (boxplot));
      }
  }
  
@@@ -568,14 -674,16 +568,14 @@@ output_examine (const struct dictionar
        if ( cmd.sbc_percentiles)
        show_percentiles (dependent_vars, n_dependent_vars, factor);
  
 -      if (cmd.a_plot[XMN_PLT_BOXPLOT] &&
 -        cmd.cmp == XMN_GROUPS)
 -      show_boxplot_groups (dependent_vars, n_dependent_vars, factor);
 -
 -
 -      if (cmd.a_plot[XMN_PLT_BOXPLOT] &&
 -        cmd.cmp == XMN_VARIABLES)
 -      show_boxplot_variables (dependent_vars, n_dependent_vars,
 -                              factor);
 -
 +      if (cmd.a_plot[XMN_PLT_BOXPLOT])
 +        {
 +          if (cmd.cmp == XMN_GROUPS)
 +            show_boxplot_groups (dependent_vars, n_dependent_vars, factor);
 +          else if (cmd.cmp == XMN_VARIABLES)
 +            show_boxplot_variables (dependent_vars, n_dependent_vars, factor);
 +        }
 +      
        if (cmd.a_plot[XMN_PLT_HISTOGRAM])
        show_histogram (dependent_vars, n_dependent_vars, factor);
  
@@@ -881,13 -989,15 +881,13 @@@ examine_group (struct cmd_examine *cmd
  
          metric->n_ptiles = percentile_list.n_data;
  
 -        metric->ptl = xcalloc (metric->n_ptiles,
 -                               sizeof (struct percentile *));
 +        metric->ptl = xcalloc (metric->n_ptiles, sizeof *metric->ptl);
  
          metric->quartiles = xcalloc (3, sizeof (*metric->quartiles));
  
          for (i = 0 ; i < metric->n_ptiles; ++i)
            {
 -            metric->ptl[i] = (struct percentile *)
 -              percentile_create (percentile_list.data[i] / 100.0, metric->n_valid);
 +            metric->ptl[i] = percentile_create (percentile_list.data[i] / 100.0, metric->n_valid);
  
              if ( percentile_list.data[i] == 25)
                metric->quartiles[0] = metric->ptl[i];
              n_os ++;
            }
  
 -        os = xcalloc (sizeof (struct order_stats *), n_os);
 +          os = xcalloc (n_os, sizeof *os);
  
          for (i = 0 ; i < metric->n_ptiles ; ++i )
            {
 -            os[i] = (struct order_stats *) metric->ptl[i];
 +            os[i] = &metric->ptl[i]->parent;
            }
  
 -        os[i] = (struct order_stats *) metric->tukey_hinges;
 -        os[i+1] = (struct order_stats *) metric->trimmed_mean;
 +        os[i] = &metric->tukey_hinges->parent;
 +        os[i+1] = &metric->trimmed_mean->parent;
  
          if (cmd->a_plot[XMN_PLT_NPPLOT])
 -          os[i+2] = metric->np;
 +          os[i+2] = &metric->np->parent;
  
          order_stats_accumulate (os, n_os,
                                  casereader_clone (metric->up_reader),
            {
              struct factor_metrics *metric = &result->metrics[v];
              if ( metric->histogram)
 -              histogram_add ((struct histogram *) metric->histogram,
 +              histogram_add (metric->histogram,
                               case_data (c, dependent_vars[v])->f, weight);
            }
          case_unref (c);
          struct factor_metrics *metric = &result->metrics[v];
            int n_vals = caseproto_get_n_widths (casereader_get_proto (
                                                   metric->up_reader));
 +          struct order_stats *os;
  
          metric->box_whisker =
 -          box_whisker_create ((struct tukey_hinges *) metric->tukey_hinges,
 -                              cmd->v_id, n_vals - 1);
 +          box_whisker_create ( metric->tukey_hinges, cmd->v_id, n_vals - 1);
  
 -        order_stats_accumulate ((struct order_stats **) &metric->box_whisker,
 -                                1,
 +          os = &metric->box_whisker->parent;
 +        order_stats_accumulate ( &os, 1,
                                  casereader_clone (metric->up_reader),
                                  wv, dependent_vars[v], MV_ANY);
        }
@@@ -1132,10 -1242,10 +1132,10 @@@ show_summary (const struct variable **d
  
    n_cols = heading_columns + 6;
  
 -  tbl = tab_create (n_cols, n_rows, 0);
 +  tbl = tab_create (n_cols, n_rows);
    tab_headers (tbl, heading_columns, 0, heading_rows, 0);
  
 -  tab_dim (tbl, tab_natural_dimensions, NULL);
 +  tab_dim (tbl, tab_natural_dimensions, NULL, NULL);
  
    /* Outline the box */
    tab_box (tbl,
@@@ -1369,10 -1479,10 +1369,10 @@@ show_descriptives (const struct variabl
  
    n_cols = heading_columns + 2;
  
 -  tbl = tab_create (n_cols, n_rows, 0);
 +  tbl = tab_create (n_cols, n_rows);
    tab_headers (tbl, heading_columns, 0, heading_rows, 0);
  
 -  tab_dim (tbl, tab_natural_dimensions, NULL);
 +  tab_dim (tbl, tab_natural_dimensions, NULL, NULL);
  
    /* Outline the box */
    tab_box (tbl,
          tab_double (tbl, n_cols - 2,
                     heading_rows + row_var_start + 3 + i * DESCRIPTIVE_ROWS,
                     TAB_CENTER,
 -                   trimmed_mean_calculate ((struct trimmed_mean *) result->metrics[v].trimmed_mean),
 +                   trimmed_mean_calculate (result->metrics[v].trimmed_mean),
                     NULL);
  
  
@@@ -1681,10 -1791,10 +1681,10 @@@ show_extremes (const struct variable **
  
    n_cols = heading_columns + 2;
  
 -  tbl = tab_create (n_cols, n_rows, 0);
 +  tbl = tab_create (n_cols, n_rows);
    tab_headers (tbl, heading_columns, 0, heading_rows, 0);
  
 -  tab_dim (tbl, tab_natural_dimensions, NULL);
 +  tab_dim (tbl, tab_natural_dimensions, NULL, NULL);
  
    /* Outline the box */
    tab_box (tbl,
              min_ll = ll_next (min_ll);
            }
  
          max_ll = ll_head (extrema_list (result->metrics[v].maxima));
          for (e = 0; e < cmd.st_n;)
            {
@@@ -1886,10 -1995,10 +1885,10 @@@ show_percentiles (const struct variabl
  
    n_cols = heading_columns + n_percentiles;
  
 -  tbl = tab_create (n_cols, n_rows, 0);
 +  tbl = tab_create (n_cols, n_rows);
    tab_headers (tbl, heading_columns, 0, heading_rows, 0);
  
 -  tab_dim (tbl, tab_natural_dimensions, NULL);
 +  tab_dim (tbl, tab_natural_dimensions, NULL, NULL);
  
    /* Outline the box */
    tab_box (tbl,
  
          tab_vline (tbl, TAL_1, n_cols - n_percentiles -1, heading_rows, n_rows - 1);
  
 -        tukey_hinges_calculate ((struct tukey_hinges *) result->metrics[v].tukey_hinges,
 -                                hinges);
 +        tukey_hinges_calculate (result->metrics[v].tukey_hinges, hinges);
  
          for (j = 0; j < n_percentiles; ++j)
            {
index 76ba5d3f1f874c4bd720f33f02b20e82b9642195,5a704d0d019f1f0d723aac1c8b81b455f02c0f7a..e1d6fb0e3dfcaa95518dc2f60b346da92199887b
@@@ -612,14 -612,13 +612,14 @@@ postcalc (const struct dataset *ds
  
          hist = freq_tab_to_hist (ft,v);
  
 -        histogram_plot_n (hist, var_to_string(v),
 +          chart_submit (histogram_chart_create (
 +                          hist, var_to_string(v),
                          vf->tab.valid_cases,
                          d[frq_mean],
                          d[frq_stddev],
 -                        normal);
 +                        normal));
  
 -        statistic_destroy ((struct statistic *)hist);
 +        statistic_destroy (&hist->parent);
        }
  
        if ( chart == GFT_PIE)
@@@ -1001,39 -1000,26 +1001,39 @@@ compare_freq_alpha_d (const void *a_, c
  \f
  /* Frequency table display. */
  
 +struct full_dim_aux
 +  {
 +    bool show_labels;
 +  };
 +
  /* Sets the widths of all the columns and heights of all the rows in
     table T for driver D. */
  static void
 -full_dim (struct tab_table *t, struct outp_driver *d, void *aux UNUSED)
 +full_dim (struct tab_rendering *r, void *aux_)
  {
 -  int i = 0;
 -  int columns = 5;
 +  const struct outp_driver *d = r->driver;
 +  const struct tab_table *t = r->table;
 +  const struct full_dim_aux *aux = aux_;
 +  int i;
  
 -  if (cmd.labels == FRQ_LABELS)
 +  for (i = 0; i < tab_nc (t); i++)
      {
 -    t->w[0] = MIN (tab_natural_width (t, d, 0), d->prop_em_width * 15);
 -      i = 1;
 -      columns ++;
 +      r->w[i] = tab_natural_width (r, i);
 +      if (aux->show_labels && i == 0)
 +        r->w[i] = MIN (r->w[i], d->prop_em_width * 15);
 +      else
 +        r->w[i] = MAX (r->w[i], d->prop_em_width * 8);
      }
  
 -  for (;i < columns; i++)
 -    t->w[i] = MAX (tab_natural_width (t, d, i), d->prop_em_width * 8);
 +  for (i = 0; i < tab_nr (t); i++)
 +    r->h[i] = d->font_height;
 +}
  
 -  for (i = 0; i < t->nr; i++)
 -    t->h[i] = d->font_height;
 +static void
 +full_dim_free (void *aux_)
 +{
 +  struct full_dim_aux *aux = aux_;
 +  free (aux);
  }
  
  /* Displays a full frequency table for variable V. */
@@@ -1046,56 -1032,34 +1046,39 @@@ dump_full (const struct variable *v, co
    struct freq_tab *ft;
    struct freq_mutable *f;
    struct tab_table *t;
-   int r;
+   int r, x;
    double cum_total = 0.0;
    double cum_freq = 0.0;
  
-   struct init
-     {
-       int c, r;
-       const char *s;
-     };
-   const struct init *p;
-   static const struct init vec[] =
-   {
-     {4, 0, N_("Valid")},
-     {5, 0, N_("Cum")},
-     {1, 1, N_("Value")},
-     {2, 1, N_("Frequency")},
-     {3, 1, N_("Percent")},
-     {4, 1, N_("Percent")},
-     {5, 1, N_("Percent")},
-     {0, 0, NULL},
-     {1, 0, NULL},
-     {2, 0, NULL},
-     {3, 0, NULL},
-     {-1, -1, NULL},
+   static const char *headings[] = {
+     N_("Value"),
+     N_("Frequency"),
+     N_("Percent"),
+     N_("Valid Percent"),
+     N_("Cum Percent")
    };
  
    const bool lab = (cmd.labels == FRQ_LABELS);
  
 +  struct full_dim_aux *aux;
 +
    vf = get_var_freqs (v);
    ft = &vf->tab;
    n_categories = ft->n_valid + ft->n_missing;
-   t = tab_create (5 + lab, n_categories + 3);
-   tab_headers (t, 0, 0, 2, 0);
 -  t = tab_create (5 + lab, n_categories + 2, 0);
++  t = tab_create (5 + lab, n_categories + 2);
+   tab_headers (t, 0, 0, 1, 0);
 -  tab_dim (t, full_dim, NULL);
 +
 +  aux = xmalloc (sizeof *aux);
 +  aux->show_labels = lab;
 +  tab_dim (t, full_dim, full_dim_free, aux);
  
    if (lab)
-     tab_text (t, 0, 1, TAB_CENTER | TAT_TITLE, _("Value Label"));
+     tab_text (t, 0, 0, TAB_CENTER | TAT_TITLE, _("Value Label"));
  
-   for (p = vec; p->s; p++)
-     tab_text (t, lab ? p->c : p->c - 1, p->r,
-                 TAB_CENTER | TAT_TITLE, gettext (p->s));
+   for (x = 0; x < 5; x++)
+     tab_text (t, lab + x, 0, TAB_CENTER | TAT_TITLE, gettext (headings[x]));
  
-   r = 2;
+   r = 1;
    for (f = ft->valid; f < ft->missing; f++)
      {
        double percent, valid_percent;
    tab_box (t, TAL_1, TAL_1,
           cmd.spaces == FRQ_SINGLE ? -1 : TAL_GAP, TAL_1,
           0, 0, 4 + lab, r);
-   tab_hline (t, TAL_2, 0, 4 + lab, 2);
+   tab_hline (t, TAL_2, 0, 4 + lab, 1);
    tab_hline (t, TAL_2, 0, 4 + lab, r);
    tab_joint_text (t, 0, r, 0 + lab, r, TAB_RIGHT | TAT_TITLE, _("Total"));
    tab_vline (t, TAL_0, 1, r, r);
  /* Sets the widths of all the columns and heights of all the rows in
     table T for driver D. */
  static void
 -condensed_dim (struct tab_table *t, struct outp_driver *d, void *aux UNUSED)
 +condensed_dim (struct tab_rendering *r, void *aux UNUSED)
  {
 -  int cum_w = MAX (outp_string_width (d, _("Cum"), OUTP_PROPORTIONAL),
 -                 MAX (outp_string_width (d, _("Cum"), OUTP_PROPORTIONAL),
 -                      outp_string_width (d, "000", OUTP_PROPORTIONAL)));
 +  struct outp_driver *d = r->driver;
 +  const struct tab_table *t = r->table;
 +
 +  int cum_width = outp_string_width (d, _("Cum"), OUTP_PROPORTIONAL);
 +  int zeros_width = outp_string_width (d, "000", OUTP_PROPORTIONAL);
 +  int max_width = MAX (cum_width, zeros_width);
  
    int i;
  
    for (i = 0; i < 2; i++)
 -    t->w[i] = MAX (tab_natural_width (t, d, i), d->prop_em_width * 8);
 +    {
 +      r->w[i] = tab_natural_width (r, i);
 +      r->w[i] = MAX (r->w[i], d->prop_em_width * 8);
 +    }
    for (i = 2; i < 4; i++)
 -    t->w[i] = cum_w;
 -  for (i = 0; i < t->nr; i++)
 -    t->h[i] = d->font_height;
 +    r->w[i] = max_width;
 +  for (i = 0; i < tab_nr (t); i++)
 +    r->h[i] = d->font_height;
  }
  
  /* Display condensed frequency table for variable V. */
@@@ -1195,7 -1153,7 +1178,7 @@@ dump_condensed (const struct variable *
    vf = get_var_freqs (v);
    ft = &vf->tab;
    n_categories = ft->n_valid + ft->n_missing;
 -  t = tab_create (4, n_categories + 2, 0);
 +  t = tab_create (4, n_categories + 2);
  
    tab_headers (t, 0, 0, 2, 0);
    tab_text (t, 0, 1, TAB_CENTER | TAT_TITLE, _("Value"));
    tab_text (t, 2, 1, TAB_CENTER | TAT_TITLE, _("Pct"));
    tab_text (t, 3, 0, TAB_CENTER | TAT_TITLE, _("Cum"));
    tab_text (t, 3, 1, TAB_CENTER | TAT_TITLE, _("Pct"));
 -  tab_dim (t, condensed_dim, NULL);
 +  tab_dim (t, condensed_dim, NULL, NULL);
  
    r = 2;
    for (f = ft->valid; f < ft->missing; f++)
           0, 0, 3, r - 1);
    tab_hline (t, TAL_2, 0, 3, 2);
    tab_title (t, "%s", var_to_string (v));
 -  tab_columns (t, SOM_COL_DOWN, 1);
 +  tab_columns (t, SOM_COL_DOWN);
    tab_submit (t);
  }
  \f
@@@ -1401,8 -1359,8 +1384,8 @@@ dump_statistics (const struct variable 
      }
    calc_stats (v, stat_value);
  
 -  t = tab_create (3, n_stats + n_percentiles + 2, 0);
 -  tab_dim (t, tab_natural_dimensions, NULL);
 +  t = tab_create (3, n_stats + n_percentiles + 2);
 +  tab_dim (t, tab_natural_dimensions, NULL, NULL);
  
    tab_box (t, TAL_1, TAL_1, -1, -1 , 0 , 0 , 2, tab_nr(t) - 1) ;
  
                  var_get_print_format (v));
      }
  
 -  tab_columns (t, SOM_COL_DOWN, 1);
 +  tab_columns (t, SOM_COL_DOWN);
    if (show_varname)
      tab_title (t, "%s", var_to_string (v));
    else
@@@ -1462,7 -1420,7 +1445,7 @@@ freq_tab_to_hist (const struct freq_ta
    double x_min = DBL_MAX;
    double x_max = -DBL_MAX;
  
 -  struct statistic *hist;
 +  struct histogram *hist;
    const double bins = 11;
  
    struct hsh_iterator hi;
    for( i = 0 ; i < ft->n_valid ; ++i )
      {
        frq = &ft->valid[i];
 -      histogram_add ((struct histogram *)hist, frq->value.f, frq->count);
 +      histogram_add (hist, frq->value.f, frq->count);
      }
  
 -  return (struct histogram *)hist;
 +  return hist;
  }
  
  
@@@ -1519,7 -1477,7 +1502,7 @@@ freq_tab_to_slice_array(const struct fr
  
        ds_init_empty (&slices[i].label);
        var_append_value_name (var, &frq->value, &slices[i].label);
 -      slices[i].magnetude = frq->count;
 +      slices[i].magnitude = frq->count;
      }
  
    return slices;
@@@ -1536,12 -1494,14 +1519,12 @@@ do_piechart(const struct variable *var
  
    slices = freq_tab_to_slice_array(frq_tab, var, &n_slices);
  
 -  piechart_plot(var_to_string(var), slices, n_slices);
 +  chart_submit (piechart_create (var_to_string(var), slices, n_slices));
  
    for (i = 0 ; i < n_slices ; ++i )
 -    {
 -      ds_destroy (&slices[i].label);
 -    }
 +    ds_destroy (&slices[i].label);
  
 -  free(slices);
 +  free (slices);
  }
  
  
index 34bdc6f0940724dd4420a1594b00514ad306de30,41a23f3e2580ebd9a9aac6ff289b89803c6f8da2..b61ae586b488292d23fda2b8ee9b96daab4d37f2
@@@ -149,8 -149,8 +149,8 @@@ reg_stats_r (pspp_linreg_cache * c
    rsq = c->ssm / c->sst;
    adjrsq = 1.0 - (1.0 - rsq) * (c->n_obs - 1.0) / (c->n_obs - c->n_indeps);
    std_error = sqrt (pspp_linreg_mse (c));
 -  t = tab_create (n_cols, n_rows, 0);
 -  tab_dim (t, tab_natural_dimensions, NULL);
 +  t = tab_create (n_cols, n_rows);
 +  tab_dim (t, tab_natural_dimensions, NULL, NULL);
    tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, n_cols - 1, n_rows - 1);
    tab_hline (t, TAL_2, 0, n_cols - 1, 1);
    tab_vline (t, TAL_2, 2, 0, n_rows - 1);
@@@ -191,9 -191,9 +191,9 @@@ reg_stats_coeff (pspp_linreg_cache * c
    assert (c != NULL);
    n_rows = c->n_coeffs + 3;
  
 -  t = tab_create (n_cols, n_rows, 0);
 +  t = tab_create (n_cols, n_rows);
    tab_headers (t, 2, 0, 1, 0);
 -  tab_dim (t, tab_natural_dimensions, NULL);
 +  tab_dim (t, tab_natural_dimensions, NULL, NULL);
    tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, n_cols - 1, n_rows - 1);
    tab_hline (t, TAL_2, 0, n_cols - 1, 1);
    tab_vline (t, TAL_2, 2, 0, n_rows - 1);
@@@ -288,9 -288,9 +288,9 @@@ reg_stats_anova (pspp_linreg_cache * c
    struct tab_table *t;
  
    assert (c != NULL);
 -  t = tab_create (n_cols, n_rows, 0);
 +  t = tab_create (n_cols, n_rows);
    tab_headers (t, 2, 0, 1, 0);
 -  tab_dim (t, tab_natural_dimensions, NULL);
 +  tab_dim (t, tab_natural_dimensions, NULL, NULL);
  
    tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, n_cols - 1, n_rows - 1);
  
@@@ -379,9 -379,9 +379,9 @@@ reg_stats_bcov (pspp_linreg_cache * c
    assert (c != NULL);
    n_cols = c->n_indeps + 1 + 2;
    n_rows = 2 * (c->n_indeps + 1);
 -  t = tab_create (n_cols, n_rows, 0);
 +  t = tab_create (n_cols, n_rows);
    tab_headers (t, 2, 0, 1, 0);
 -  tab_dim (t, tab_natural_dimensions, NULL);
 +  tab_dim (t, tab_natural_dimensions, NULL, NULL);
    tab_box (t, TAL_2, TAL_2, -1, TAL_1, 0, 0, n_cols - 1, n_rows - 1);
    tab_hline (t, TAL_2, 0, n_cols - 1, 1);
    tab_vline (t, TAL_2, 2, 0, n_rows - 1);
@@@ -914,7 -914,7 +914,7 @@@ run_regression (struct casereader *inpu
      }
    lopts.get_depvar_mean_std = 1;
  
-   lopts.get_indep_mean_std = xnmalloc (n_variables, sizeof (int));
    indep_vars = xnmalloc (n_variables, sizeof *indep_vars);
  
    for (k = 0; k < cmd->n_dependent; k++)
            design_matrix_create (n_indep,
                                  (const struct variable **) indep_vars,
                                  n_data);
+         lopts.get_indep_mean_std = xnmalloc (X->m->size2, sizeof (int));
          for (i = 0; i < X->m->size2; i++)
            {
              lopts.get_indep_mean_std[i] = 1;
  
          gsl_vector_free (Y);
          design_matrix_destroy (X);
+         free (lopts.get_indep_mean_std);
        }
        else
        {
      }
    free (mom);
    free (indep_vars);
-   free (lopts.get_indep_mean_std);
    casereader_destroy (input);
  
    return true;
index 8d2b2122d1bda6eca09682ba5c98a6df4c5f31b2,c448d52ea035c3d163bef9bf343a8d6b9609f904..d417d31c0d26e944b9548756e05e2baf1ea178ad
@@@ -47,6 -47,7 +47,7 @@@
  #include <output/table.h>
  #include <data/format.h>
  
+ #include "minmax.h"
  #include "xalloc.h"
  #include "xmemdup0.h"
  
@@@ -475,13 -476,13 +476,13 @@@ static voi
  ssbox_base_init (struct ssbox *this, int cols, int rows)
  {
    this->finalize = ssbox_base_finalize;
 -  this->t = tab_create (cols, rows, 0);
 +  this->t = tab_create (cols, rows);
  
 -  tab_columns (this->t, SOM_COL_DOWN, 1);
 +  tab_columns (this->t, SOM_COL_DOWN);
    tab_headers (this->t, 0, 0, 1, 0);
    tab_box (this->t, TAL_2, TAL_2, TAL_0, TAL_1, 0, 0, cols - 1, rows - 1);
    tab_hline (this->t, TAL_2, 0, cols- 1, 1);
 -  tab_dim (this->t, tab_natural_dimensions, NULL);
 +  tab_dim (this->t, tab_natural_dimensions, NULL, NULL);
  }
  \f
  /* ssbox implementations. */
@@@ -506,7 -507,7 +507,7 @@@ ssbox_one_sample_init (struct ssbox *th
    tab_text (this->t, 1, 0, TAB_CENTER | TAT_TITLE, _("N"));
    tab_text (this->t, 2, 0, TAB_CENTER | TAT_TITLE, _("Mean"));
    tab_text (this->t, 3, 0, TAB_CENTER | TAT_TITLE, _("Std. Deviation"));
-   tab_text (this->t, 4, 0, TAB_CENTER | TAT_TITLE, _("SE. Mean"));
+   tab_text (this->t, 4, 0, TAB_CENTER | TAT_TITLE, _("S.E. Mean"));
  }
  
  /* Initialize the independent samples ssbox */
@@@ -526,7 -527,7 +527,7 @@@ ssbox_independent_samples_init (struct 
    tab_text (this->t, 2, 0, TAB_CENTER | TAT_TITLE, _("N"));
    tab_text (this->t, 3, 0, TAB_CENTER | TAT_TITLE, _("Mean"));
    tab_text (this->t, 4, 0, TAB_CENTER | TAT_TITLE, _("Std. Deviation"));
-   tab_text (this->t, 5, 0, TAB_CENTER | TAT_TITLE, _("SE. Mean"));
+   tab_text (this->t, 5, 0, TAB_CENTER | TAT_TITLE, _("S.E. Mean"));
  }
  
  /* Populate the ssbox for independent samples */
@@@ -625,7 -626,7 +626,7 @@@ ssbox_paired_init (struct ssbox *this, 
    tab_text (this->t, 2, 0, TAB_CENTER | TAT_TITLE, _("Mean"));
    tab_text (this->t, 3, 0, TAB_CENTER | TAT_TITLE, _("N"));
    tab_text (this->t, 4, 0, TAB_CENTER | TAT_TITLE, _("Std. Deviation"));
-   tab_text (this->t, 5, 0, TAB_CENTER | TAT_TITLE, _("SE. Mean"));
+   tab_text (this->t, 5, 0, TAB_CENTER | TAT_TITLE, _("S.E. Mean"));
  }
  
  /* Populate the ssbox for paired values */
@@@ -1067,11 -1068,11 +1068,11 @@@ trbox_base_init (struct trbox *self, si
    const size_t rows = 3 + data_rows;
  
    self->finalize = trbox_base_finalize;
 -  self->t = tab_create (cols, rows, 0);
 +  self->t = tab_create (cols, rows);
    tab_headers (self->t, 0, 0, 3, 0);
    tab_box (self->t, TAL_2, TAL_2, TAL_0, TAL_0, 0, 0, cols - 1, rows - 1);
    tab_hline (self->t, TAL_2, 0, cols- 1, 3);
 -  tab_dim (self->t, tab_natural_dimensions, NULL);
 +  tab_dim (self->t, tab_natural_dimensions, NULL, NULL);
  }
  
  /* Base finalizer for the trbox */
@@@ -1091,14 -1092,14 +1092,14 @@@ pscbox (struct t_test_proc *proc
  
    struct tab_table *table;
  
 -  table = tab_create (cols, rows, 0);
 +  table = tab_create (cols, rows);
  
 -  tab_columns (table, SOM_COL_DOWN, 1);
 +  tab_columns (table, SOM_COL_DOWN);
    tab_headers (table, 0, 0, 1, 0);
    tab_box (table, TAL_2, TAL_2, TAL_0, TAL_1, 0, 0, cols - 1, rows - 1);
    tab_hline (table, TAL_2, 0, cols - 1, 1);
    tab_vline (table, TAL_2, 2, 0, rows - 1);
 -  tab_dim (table, tab_natural_dimensions, NULL);
 +  tab_dim (table, tab_natural_dimensions, NULL, NULL);
    tab_title (table, _("Paired Samples Correlations"));
  
    /* column headings */
    for (i = 0; i < proc->n_pairs; i++)
      {
        struct pair *pair = &proc->pairs[i];
+       double df = pair->n - 2;
        double p, q;
-       double df = pair->n -2;
-       double correlation_t = (pair->correlation * sqrt (df) /
-                               sqrt (1 - pow2 (pair->correlation)));
+       /* corr2 will mathematically always be in the range [0, 1.0].  Inaccurate
+          calculations sometimes cause it to be slightly greater than 1.0, so
+          force it into the correct range to avoid NaN from sqrt(). */
+       double corr2 = MIN (1.0, pow2 (pair->correlation));
+       double correlation_t = pair->correlation * sqrt (df) / sqrt (1 - corr2);
  
        /* row headings */
        tab_text_format (table, 0, i + 1, TAB_LEFT | TAT_TITLE,
index db3d89ba879e2ee015b36dbb979725f1ae001c7e,fbf1925e635e165c3c096d119bace8123fa0d5bc..334818b4cad9428975f8c2e1623ea567ff57ac5c
@@@ -1,5 -1,5 +1,5 @@@
  /* PSPP - a program for statistical analysis.
-    Copyright  (C) 2004, 2009 Free Software Foundation, Inc.
+    Copyright (C) 2004, 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
@@@ -18,6 -18,7 +18,6 @@@
  #include <config.h>
  
  #include <stdio.h>
 -#include <plot.h>
  #include <math.h>
  #include <gsl/gsl_histogram.h>
  #include <gsl/gsl_randist.h>
  
  #include <output/charts/plot-hist.h>
  #include <output/charts/plot-chart.h>
 +#include <output/chart-provider.h>
  
  #include <data/variable.h>
 +#include <libpspp/cast.h>
  #include <libpspp/hash.h>
  #include <output/chart.h>
  #include <math/histogram.h>
  #include "gettext.h"
  #define _(msgid) gettext (msgid)
  
 +static const struct chart_class histogram_chart_class;
 +
  /* Write the legend of the chart */
  static void
 -histogram_write_legend (struct chart *ch, double n, double mean, double stddev)
 +histogram_write_legend (cairo_t *cr, const struct chart_geometry *geom,
 +                        double n, double mean, double stddev)
  {
 -  char buf[100];
 -
 -  if (!ch)
 -    return ;
 -
 -  pl_savestate_r (ch->lp);
 +  double y = geom->data_bottom;
 +  cairo_save (cr);
  
 -  sprintf (buf, "N = %.2f", n);
 -  pl_move_r (ch->lp, ch->legend_left, ch->data_bottom);
 -  pl_alabel_r (ch->lp, 0, 'b', buf);
 +  if (n != SYSMIS)
 +    {
 +      char *buf = xasprintf ("N = %.2f", n);
 +      cairo_move_to (cr, geom->legend_left, y);
 +      chart_label (cr, 'l', 'b', geom->font_size, buf);
 +      y += geom->font_size * 1.5;
 +      free (buf);
 +    }
  
 -  sprintf (buf, "Mean = %.1f", mean);
 -  pl_fmove_r (ch->lp,ch->legend_left,ch->data_bottom + ch->font_size * 1.5);
 -  pl_alabel_r (ch->lp, 0, 'b', buf);
 +  if (mean != SYSMIS)
 +    {
 +      char *buf = xasprintf ("Mean = %.1f", mean);
 +      cairo_move_to (cr,geom->legend_left, y);
 +      chart_label (cr, 'l', 'b', geom->font_size, buf);
 +      y += geom->font_size * 1.5;
 +      free (buf);
 +    }
  
 -  sprintf (buf, "Std. Dev = %.2f", stddev);
 -  pl_fmove_r (ch->lp, ch->legend_left, ch->data_bottom + ch->font_size * 1.5 * 2);
 -  pl_alabel_r (ch->lp, 0, 'b', buf);
 +  if (stddev != SYSMIS)
 +    {
 +      char *buf = xasprintf ("Std. Dev = %.2f", stddev);
 +      cairo_move_to (cr, geom->legend_left, y);
 +      chart_label (cr, 'l', 'b', geom->font_size, buf);
 +      free (buf);
 +    }
  
 -  pl_restorestate_r (ch->lp);
 +  cairo_restore (cr);
  }
  
 -static void hist_draw_bar (struct chart *ch, const struct histogram *hist, int bar);
 -
 -
  static void
 -hist_draw_bar (struct chart *ch, const struct histogram *hist, int bar)
 +hist_draw_bar (cairo_t *cr, const struct chart_geometry *geom,
 +               const gsl_histogram *h, int bar)
  {
 -  if (!ch)
 -    return ;
 -
 -  {
 -    double upper;
 -    double lower;
 -    double height;
 -
 -    const size_t bins = gsl_histogram_bins (hist->gsl_hist);
 -    const double x_pos = (ch->data_right - ch->data_left) * bar / (double) bins ;
 -    const double width = (ch->data_right - ch->data_left) / (double) bins ;
 -
 -    assert ( 0 == gsl_histogram_get_range (hist->gsl_hist, bar, &lower, &upper));
 -
 -    assert ( upper >= lower);
 -
 -    height = gsl_histogram_get (hist->gsl_hist, bar) *
 -     (ch->data_top - ch->data_bottom) / gsl_histogram_max_val (hist->gsl_hist);
 -
 -    pl_savestate_r (ch->lp);
 -    pl_move_r (ch->lp,ch->data_left, ch->data_bottom);
 -    pl_fillcolorname_r (ch->lp, ch->fill_colour);
 -    pl_filltype_r (ch->lp,1);
 -
 -
 -    pl_fboxrel_r (ch->lp,
 -               x_pos, 0,
 -               x_pos + width, height);
 -
 -    pl_restorestate_r (ch->lp);
 -
 -    draw_tick (ch, TICK_ABSCISSA,
 -               x_pos + width / 2.0, "%g", (upper + lower) / 2.0);
 -  }
 +  double upper;
 +  double lower;
 +  double height;
 +
 +  const size_t bins = gsl_histogram_bins (h);
 +  const double x_pos = (geom->data_right - geom->data_left) * bar / (double) bins ;
 +  const double width = (geom->data_right - geom->data_left) / (double) bins ;
 +
 +  assert ( 0 == gsl_histogram_get_range (h, bar, &lower, &upper));
 +
 +  assert ( upper >= lower);
 +
 +  height = gsl_histogram_get (h, bar) *
 +    (geom->data_top - geom->data_bottom) / gsl_histogram_max_val (h);
 +
 +  cairo_rectangle (cr, geom->data_left + x_pos, geom->data_bottom,
 +                   width, height);
 +  cairo_save (cr);
 +  cairo_set_source_rgb (cr,
 +                        geom->fill_colour.red / 255.0,
 +                        geom->fill_colour.green / 255.0,
 +                        geom->fill_colour.blue / 255.0);
 +  cairo_fill_preserve (cr);
 +  cairo_restore (cr);
 +  cairo_stroke (cr);
 +
 +  draw_tick (cr, geom, TICK_ABSCISSA,
 +             x_pos + width / 2.0, "%g", (upper + lower) / 2.0);
  }
  
 -
 -
 -void
 -histogram_plot (const struct histogram *hist,
 -              const char *label,
 -              const struct moments1 *m)
 +struct histogram_chart
 +  {
 +    struct chart chart;
 +    gsl_histogram *gsl_hist;
 +    char *label;
 +    double n;
 +    double mean;
 +    double stddev;
 +    bool show_normal;
 +  };
 +
 +/* Plots a histogram of the data in HIST with the given LABEL.
 +   Labels the histogram with each of N, MEAN, and STDDEV that is
 +   not SYSMIS.  If all three are not SYSMIS and SHOW_NORMAL is
 +   true, also draws a normal curve on the histogram. */
 +struct chart *
 +histogram_chart_create (const struct histogram *hist, const char *label,
 +                        double n, double mean, double stddev,
 +                        bool show_normal)
  {
 -  double mean, var, n;
 -
 -  moments1_calculate (m, &n, &mean, &var, NULL,  NULL);
 -
 -  histogram_plot_n (hist, label, n, mean, sqrt(var), m);
 +  struct histogram_chart *h;
 +
 +  h = xmalloc (sizeof *h);
 +  chart_init (&h->chart, &histogram_chart_class);
 +  h->gsl_hist = hist->gsl_hist ? gsl_histogram_clone (hist->gsl_hist) : NULL;
 +  h->label = xstrdup (label);
 +  h->n = n;
 +  h->mean = mean;
 +  h->stddev = stddev;
 +  h->show_normal = show_normal;
 +  return &h->chart;
  }
  
 -
 -/* This function is deprecated.  Don't use it in new code */
 -void
 -histogram_plot_n (const struct histogram *hist,
 -                const char *label,
 -                double n, double mean, double stddev,
 -                bool show_normal)
 +static void
 +histogram_chart_draw (const struct chart *chart, cairo_t *cr,
 +                      struct chart_geometry *geom)
  {
 +  struct histogram_chart *h = UP_CAST (chart, struct histogram_chart, chart);
    int i;
    int bins;
  
 -  struct chart *ch = chart_create ();
 -
 -  chart_write_title (ch, _("HISTOGRAM"));
 +  chart_write_title (cr, geom, _("HISTOGRAM"));
  
 -  chart_write_ylabel (ch, _("Frequency"));
 -  chart_write_xlabel (ch, label);
 +  chart_write_ylabel (cr, geom, _("Frequency"));
 +  chart_write_xlabel (cr, geom, h->label);
  
 -  if ( ! hist ) /* If this happens, probably all values are SYSMIS */
 +  if (h->gsl_hist == NULL)
      {
 -      chart_submit (ch);
 +      /* Probably all values are SYSMIS. */
        return;
      }
 -  else
 -    {
 -      bins = gsl_histogram_bins (hist->gsl_hist);
 -    }
  
 -  chart_write_yscale (ch, 0, gsl_histogram_max_val (hist->gsl_hist), 5);
 +  bins = gsl_histogram_bins (h->gsl_hist);
 +
 +  chart_write_yscale (cr, geom, 0, gsl_histogram_max_val (h->gsl_hist), 5);
  
 -  for ( i = 0 ; i < bins ; ++i )
 -    hist_draw_bar (ch, hist, i);
 +  for (i = 0; i < bins; i++)
 +    hist_draw_bar (cr, geom, h->gsl_hist, i);
  
 -  histogram_write_legend (ch, n, mean, stddev);
 +  histogram_write_legend (cr, geom, h->n, h->mean, h->stddev);
  
 -  if (show_normal)
 +  if (h->show_normal
 +      && h->n != SYSMIS && h->mean != SYSMIS && h->stddev != SYSMIS)
      {
        /* Draw the normal curve */
 +      double d;
 +      double x_min, x_max, not_used;
 +      double abscissa_scale;
 +      double ordinate_scale;
 +      double range;
  
 -      double d ;
 -      double x_min, x_max, not_used ;
 -      double abscissa_scale ;
 -      double ordinate_scale ;
 -      double range ;
 -
 -      gsl_histogram_get_range (hist->gsl_hist, 0, &x_min, &not_used);
 +      gsl_histogram_get_range (h->gsl_hist, 0, &x_min, &not_used);
        range = not_used - x_min;
 -      gsl_histogram_get_range (hist->gsl_hist, bins - 1, &not_used, &x_max);
 +      gsl_histogram_get_range (h->gsl_hist, bins - 1, &not_used, &x_max);
  
 -      abscissa_scale = (ch->data_right - ch->data_left) / (x_max - x_min);
 -      ordinate_scale = (ch->data_top - ch->data_bottom) /
 -      gsl_histogram_max_val (hist->gsl_hist) ;
 +      abscissa_scale = (geom->data_right - geom->data_left) / (x_max - x_min);
 +      ordinate_scale = (geom->data_top - geom->data_bottom) /
 +      gsl_histogram_max_val (h->gsl_hist);
  
 -      pl_move_r (ch->lp, ch->data_left, ch->data_bottom);
 -      for ( d = ch->data_left;
 -          d <= ch->data_right ;
 -          d += (ch->data_right - ch->data_left) / 100.0)
 +      cairo_move_to (cr, geom->data_left, geom->data_bottom);
 +      for (d = geom->data_left;
 +         d <= geom->data_right;
 +         d += (geom->data_right - geom->data_left) / 100.0)
        {
 -        const double x = (d - ch->data_left) / abscissa_scale + x_min ;
 -        const double y = n * range *
 -          gsl_ran_gaussian_pdf (x - mean, stddev);
 +        const double x = (d - geom->data_left) / abscissa_scale + x_min;
 +        const double y = h->n * range *
 +          gsl_ran_gaussian_pdf (x - h->mean, h->stddev);
  
 -        pl_fcont_r (ch->lp,  d,  ch->data_bottom  + y * ordinate_scale);
 +          cairo_line_to (cr, d, geom->data_bottom  + y * ordinate_scale);
  
        }
 -      pl_endpath_r (ch->lp);
 +      cairo_stroke (cr);
      }
 -
 -  chart_submit (ch);
  }
  
  
 +static void
 +histogram_chart_destroy (struct chart *chart)
 +{
 +  struct histogram_chart *h = UP_CAST (chart, struct histogram_chart, chart);
 +  if (h->gsl_hist != NULL)
 +    gsl_histogram_free (h->gsl_hist);
 +  free (h->label);
 +  free (h);
 +}
 +
 +static const struct chart_class histogram_chart_class =
 +  {
 +    histogram_chart_draw,
 +    histogram_chart_destroy
 +  };
diff --combined src/ui/gui/automake.mk
index 838f0d69800d7ce6d3d8f0499920216869e558ea,7c06b8e47bf33c5811f4ea486d7e27454499f47d..05f362194cc207442d902d3b63fcd6d18adeb4f6
@@@ -4,10 -4,7 +4,7 @@@ include $(top_srcdir)/src/ui/gui/sheet/
  
  bin_PROGRAMS += src/ui/gui/psppire 
  
- src_ui_gui_psppire_CFLAGS = $(GTK_CFLAGS) -Wall \
-       -DINSTALLDIR=\"$(bindir)\"  \
-       -DDOCDIR=\"$(docdir)\"  \
-       -DGDK_MULTIHEAD_SAFE=1
+ src_ui_gui_psppire_CFLAGS = $(GTK_CFLAGS) -Wall -DGDK_MULTIHEAD_SAFE=1
  
  
  src_ui_gui_psppire_LDFLAGS = \
@@@ -29,8 -26,7 +26,8 @@@ src_ui_gui_psppire_LDADD = 
        src/libpspp.la \
        src/libpspp-core.la \
        $(GTK_LIBS) \
-       @LIBINTL@
 +      $(CAIRO_LIBS) \
+       $(LIBINTL)
  
  src_ui_gui_psppiredir = $(pkgdatadir)
  
@@@ -50,36 -46,39 +47,39 @@@ INSTALL_DATA_HOOKS += install-icon
  
  uninstall-icons:
        for size in 16x16 ; do \
-           $(RM) $(themedir)/$$size/$(context)/psppicon.png ; \
+           rm -f $(themedir)/$$size/$(context)/psppicon.png ; \
        done 
        gtk-update-icon-cache --ignore-theme-index $(themedir)
  
  UNINSTALL_DATA_HOOKS += uninstall-icons
  
  
+ UI_FILES = \
+       src/ui/gui/crosstabs.ui \
+       src/ui/gui/descriptives.ui \
+       src/ui/gui/examine.ui \
+       src/ui/gui/find.ui \
+       src/ui/gui/frequencies.ui \
+       src/ui/gui/message-dialog.ui \
+       src/ui/gui/oneway.ui \
+       src/ui/gui/psppire.ui \
+       src/ui/gui/rank.ui \
+       src/ui/gui/recode.ui \
+       src/ui/gui/regression.ui \
+       src/ui/gui/reliability.ui \
+       src/ui/gui/t-test.ui \
+       src/ui/gui/text-data-import.ui \
+       src/ui/gui/var-sheet-dialogs.ui \
+       src/ui/gui/variable-info.ui
  nodist_src_ui_gui_psppire_DATA = \
-       $(top_builddir)/src/ui/gui/crosstabs.ui \
-       $(top_builddir)/src/ui/gui/descriptives-dialog.ui \
        $(top_builddir)/src/ui/gui/data-editor.ui \
-       $(top_builddir)/src/ui/gui/examine.ui \
-       $(top_builddir)/src/ui/gui/find.ui \
-       $(top_builddir)/src/ui/gui/frequencies.ui \
-       $(top_builddir)/src/ui/gui/message-dialog.ui \
-       $(top_builddir)/src/ui/gui/psppire.ui \
-       $(top_builddir)/src/ui/gui/oneway.ui \
        $(top_builddir)/src/ui/gui/output-viewer.ui \
-       $(top_builddir)/src/ui/gui/rank.ui \
-       $(top_builddir)/src/ui/gui/recode.ui \
-       $(top_builddir)/src/ui/gui/regression.ui \
-       $(top_builddir)/src/ui/gui/reliability.ui \
-       $(top_builddir)/src/ui/gui/syntax-editor.ui \
-       $(top_builddir)/src/ui/gui/text-data-import.ui \
-       $(top_builddir)/src/ui/gui/t-test.ui \
-       $(top_builddir)/src/ui/gui/var-sheet-dialogs.ui \
-       $(top_builddir)/src/ui/gui/variable-info-dialog.ui
+       $(top_builddir)/src/ui/gui/syntax-editor.ui
  
  
  dist_src_ui_gui_psppire_DATA = \
+       $(UI_FILES) \
        $(top_srcdir)/src/ui/gui/pspplogo.png \
        $(top_srcdir)/src/ui/gui/icons/value-labels.png \
        $(top_srcdir)/src/ui/gui/icons/goto-variable.png\
@@@ -219,25 -218,9 +219,9 @@@ src_ui_gui_psppire_SOURCES = 
        src/ui/gui/widget-io.h \
        src/ui/gui/widgets.c \
        src/ui/gui/widgets.h \
-       src/ui/gui/crosstabs.glade \
-       src/ui/gui/descriptives-dialog.glade \
        src/ui/gui/data-editor.glade \
-       src/ui/gui/examine.glade \
-       src/ui/gui/find.glade \
-       src/ui/gui/frequencies.glade \
-       src/ui/gui/message-dialog.glade \
-       src/ui/gui/psppire.glade \
-       src/ui/gui/oneway.glade \
        src/ui/gui/output-viewer.glade \
-       src/ui/gui/rank.glade \
-       src/ui/gui/recode.glade \
-       src/ui/gui/regression.glade \
-       src/ui/gui/reliability.glade \
-       src/ui/gui/syntax-editor.glade \
-       src/ui/gui/text-data-import.glade \
-       src/ui/gui/t-test.glade \
-       src/ui/gui/var-sheet-dialogs.glade \
-       src/ui/gui/variable-info-dialog.glade
+       src/ui/gui/syntax-editor.glade
  
  
  nodist_src_ui_gui_psppire_SOURCES = \
@@@ -261,11 -244,12 +245,12 @@@ AM_CPPFLAGS += -Isr
  
  src/ui/gui/psppire-marshal.c: src/ui/gui/marshaller-list
        echo '#include <config.h>' > $@
-       glib-genmarshal --body --prefix=psppire_marshal $< >> $@
+       glib-genmarshal --body --prefix=psppire_marshal $? >> $@
  
  src/ui/gui/psppire-marshal.h: src/ui/gui/marshaller-list
-       glib-genmarshal --header --prefix=psppire_marshal $< > $@
+       glib-genmarshal --header --prefix=psppire_marshal $? > $@
  
+ SUFFIXES += .glade .ui
  .glade.ui:
        $(top_srcdir)/lib/gtk-contrib/gtk-builder-convert $< $@
  
diff --combined src/ui/gui/psppire.c
index 928a1c92886f46030460947d0cc7c2b5a30b9501,1cd7ee803c736a740b373a53b035c7dcef6bd90a..961998d9266a8ab4da61fd4f102109606c46cc6d
@@@ -89,7 -89,6 +89,6 @@@ initialize (struct command_line_process
  {
    PsppireDict *dictionary = 0;
  
    i18n_init ();
  
    preregister_widgets ();
  
    create_icon_factory ();
  
 -  {
 -    const char *filename = output_file_name ();
 -
 -    struct string config_string;
 -
 -    ds_init_empty (&config_string);
 -
 -    ds_put_format (&config_string,
 -                 "gui:ascii:screen:squeeze=on headers=off top-margin=0 "
 -                 "bottom-margin=0 paginate=off length=auto width=auto "
 -                 "emphasis=none "
 -                 "output-file=\"%s\" append=yes", filename);
 -
 -    outp_configure_driver_line (ds_ss (&config_string));
 -
 -    unlink (filename);
 -
 -    ds_destroy (&config_string);
 -  }
 +  psppire_output_window_setup ();
  
    journal_enable ();
    textdomain (PACKAGE);
@@@ -321,3 -338,16 +320,3 @@@ parse_non_options (int key, char *arg, 
  
  
  const struct argp non_option_argp = {NULL, parse_non_options, 0, 0, 0, 0, 0};
 -
 -
 -const char *
 -output_file_name (void)
 -{
 -  const char *dir = default_output_path ();
 -  static char *filename = NULL;
 -
 -  if ( NULL == filename )
 -    filename = xasprintf ("%s%s", dir, OUTPUT_FILE_NAME);
 -
 -  return filename;
 -}
index 63b83384ada6a75162df9e8e867fc1a11896a904,9cde11c9110641e1c6f39fa1aa4de959865cb74b..81b896dc878839d44590f9e3205ebc53d5e07fb0
@@@ -14,7 -14,7 +14,7 @@@ src_ui_terminal_libui_la_SOURCES = 
        src/ui/terminal/terminal-opts.h 
  
  
- src_ui_terminal_libui_la_CFLAGS = -DINSTALLDIR=\"$(bindir)\" $(NCURSES_CFLAGS)
+ src_ui_terminal_libui_la_CFLAGS = $(NCURSES_CFLAGS)
  
  bin_PROGRAMS += src/ui/terminal/pspp
  
@@@ -25,10 -25,9 +25,10 @@@ src_ui_terminal_pspp_LDADD = 
        src/ui/libuicommon.la \
        src/libpspp.la \
        src/libpspp-core.la \
 +      $(CAIRO_LIBS) \
        $(NCURSES_LIBS) \
        $(LIBICONV) \
-       @LIBINTL@ @LIBREADLINE@
+       $(LIBINTL) $(LIBREADLINE)
  
  
  src_ui_terminal_pspp_LDFLAGS = $(PSPP_LDFLAGS) $(PG_LDFLAGS)