From: John Darrington <john@darrington.wattle.id.au>
Date: Thu, 24 Sep 2009 18:43:42 +0000 (+0200)
Subject: Merge commit 'origin/stable'
X-Git-Tag: sav-api~248^2~63
X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bd17d2af982332ee1791998361b1ac6731fe14fa;p=pspp

Merge commit 'origin/stable'

Conflicts:

	AUTHORS
	NEWS
	configure.ac
	lib/gtksheet/gtkitementry.c
	po/LINGUAS
	po/nl.po
	src/data/file-name.c
	src/data/sys-file-writer.c
	src/language/stats/crosstabs.q
	src/language/stats/examine.q
	src/language/stats/t-test.q
	src/output/charts/box-whisker.c
	src/output/charts/plot-hist.c
	src/ui/gui/output-viewer.c
	src/ui/gui/psppire.c
	src/ui/gui/psppire.h
	src/ui/terminal/main.c
---

bd17d2af982332ee1791998361b1ac6731fe14fa
diff --cc NEWS
index df10031e1d,61a493863d..1798fdd3c2
--- a/NEWS
+++ b/NEWS
@@@ -5,27 -5,91 +5,113 @@@ See the end for copying conditions
  
  Please send PSPP bug reports to bug-gnu-pspp@gnu.org.
  
 +Changes from 0.7.1 to 0.7.2:
 +
 + * Updated Perl module interface.
 +
 + * Value labels for long string variables are now supported.
 +
 + * Missing values for long string variables are now supported.
 +
 +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
 +    for setting and clear attributes.  Support for attributes has also
 +    been added to commands that read and write system files, such as
 +    SAVE and GET, as well as to the DISPLAY command.
 +
+ 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).
++>>>>>>> origin/stable:NEWS
+ 
  Changes from 0.6.0 to 0.6.1:
  
    * Statistical bug fixes:
diff --cc po/automake.mk
index 1f5ca31bd0,0000000000..56715e1ebd
mode 100644,000000..100644
--- a/po/automake.mk
+++ b/po/automake.mk
@@@ -1,54 -1,0 +1,54 @@@
 +include $(top_srcdir)/po/Makevars
 +
 +XGETTEXT=xgettext
 +MSGMERGE=msgmerge
 +MSGFMT=msgfmt
 +
- POFILES=po/en_GB.po po/nl.po
++POFILES=po/en_GB.po po/nl.po po/pt_BR.po
 +
 +POTFILE=po/$(DOMAIN).pot
 +
 +TRANSLATABLE_FILES = $(DIST_SOURCES) $(all_q_sources)
 +
 +$(POTFILE): $(TRANSLATABLE_FILES)
 +	@$(MKDIR_P) po
 +	$(XGETTEXT) --directory=$(top_srcdir) $(TRANSLATABLE_FILES) \
 +	$(XGETTEXT_OPTIONS) \
 +	--copyright-holder="$(COPYRIGHT_HOLDER)" \
 +	--package-name=$(PACKAGE) \
 +	--package-version=$(VERSION) \
 +	--msgid-bugs-address=$(MSGID_BUGS_ADDRESS) \
 +	--add-comments='TRANSLATORS:' \
 +	-o $(POTFILE)
 +
 +
 +$(POFILES): $(POTFILE)
 +	$(MSGMERGE) $(top_srcdir)/$* $< -o $@
 +
 +.po.gmo:
 +	@$(MKDIR_P) `dirname $@`
 +	$(MSGFMT) $< -o $@
 +
 +
 +GMOFILES = $(POFILES:.po=.gmo)
 +
 +ALL_LOCAL += $(GMOFILES)
 +
 +install-data-hook: $(GMOFILES)
 +	for f in $(GMOFILES); do \
 +	  lang=`echo $$f | sed -e 's%po/\(.*\)\.gmo%\1%' ` ; \
 +	  $(INSTALL) -D $$f $(DESTDIR)$(prefix)/share/locale/$$lang/LC_MESSAGES/$(DOMAIN).mo ; \
 +	done
 +	
 +
 +uninstall-hook:
 +	for f in $(GMOFILES); do \
 +	  lang=`echo $$f | sed -e 's%po/\(.*\)\.gmo%\1%' ` ; \
 +	  $(RM) $(DESTDIR)$(prefix)/share/locale/$$lang/LC_MESSAGES/$(DOMAIN).mo ; \
 +	done
 +
 +
 +EXTRA_DIST += $(POFILES) $(POTFILE)
 +
 +CLEANFILES += $(POFILES) $(GMOFILES) $(POTFILE)
 +
diff --cc src/data/file-name.c
index 601afd5579,6be5ef0afa..9122959592
--- a/src/data/file-name.c
+++ b/src/data/file-name.c
@@@ -476,7 -476,7 +476,6 @@@ default_output_path (void
  	  const char *home_drive = getenv ("HOMEDRIVE");
  	  const char *home_path = getenv ("HOMEPATH");
  
--
  	  if (home_drive != NULL && home_path != NULL)
  	    home_dir = xasprintf ("%s%s",
  				  home_drive, home_path);
@@@ -485,9 -485,16 +484,15 @@@
        if (home_dir == NULL)
  	home_dir = "c:/users/default"; /* poor default */
  
-       path = xasprintf ("%s%c", home_dir, '/');
- 
+       /* Copy home_dir into path.  Add a slash at the end but
+          only if there isn't already one there, because Windows
+          treats // specially. */
+       if (home_dir[0] == '\0'
+           || strchr ("/\\", home_dir[strlen (home_dir) - 1]) == NULL)
+         path = xasprintf ("%s%c", home_dir, '/');
+       else
+         path = xstrdup (home_dir);
  
 -
        for(i = 0; i < strlen (path); i++)
  	if (path[i] == '\\') path[i] = '/';
      }
diff --cc src/data/sys-file-writer.c
index 3fed2e0544,001b78f162..5daea89dc5
--- a/src/data/sys-file-writer.c
+++ b/src/data/sys-file-writer.c
@@@ -461,12 -435,11 +461,12 @@@ write_variable (struct sfm_writer *w, c
    /* Value label. */
    if (var_has_label (v))
      {
--      const char *label = var_get_label (v);
-       char *l = recode_string (dict_get_encoding (dict), UTF8, label, -1);
-       size_t padded_len = ROUND_UP (MIN (strlen (l), 255), 4);
-       write_int (w, padded_len);
-       write_string (w, l, padded_len);
-       free (l);
++      char *label = recode_string (dict_get_encoding (dict), UTF8, var_get_label (v), -1);
+       size_t label_len = MIN (strlen (label), 255);
+       size_t padded_len = ROUND_UP (label_len, 4);
+       write_int (w, label_len);
+       write_string (w, label, padded_len);
++      free (label);
      }
  
    /* Write the missing values, if any, range first. */
diff --cc src/language/stats/examine.q
index e8333b1cee,592bb56b13..0807794234
--- a/src/language/stats/examine.q
+++ b/src/language/stats/examine.q
@@@ -1803,205 -1453,605 +1803,204 @@@ show_extremes (const struct variable **
  	   0, 0,
  	   n_cols - 1, n_rows - 1);
  
 -  tab_hline (tbl, TAL_2, 0, n_cols - 1, heading_rows );
  
 -  tab_vline (tbl, TAL_1, heading_columns, 0, n_rows - 1);
 -  tab_vline (tbl, TAL_2, n_cols - 2, 0, n_rows - 1);
 +  tab_hline (tbl, TAL_2, 0, n_cols - 1, heading_rows );
 +  tab_hline (tbl, TAL_2, 1, n_cols - 1, heading_rows );
    tab_vline (tbl, TAL_1, n_cols - 1, 0, n_rows - 1);
  
 -  tab_text (tbl, n_cols - 2, 0, TAB_CENTER | TAT_TITLE, _ ("Statistic"));
 -  tab_text (tbl, n_cols - 1, 0, TAB_CENTER | TAT_TITLE, _ ("Std. Error"));
 +  if ( fctr->indep_var[0])
 +    tab_text (tbl, 1, 0, TAT_TITLE, var_to_string (fctr->indep_var[0]));
  
 -  tab_title (tbl, _ ("Descriptives"));
 +  if ( fctr->indep_var[1])
 +    tab_text (tbl, 2, 0, TAT_TITLE, var_to_string (fctr->indep_var[1]));
  
 -
 -  for ( i = 0 ; i < n_dep_var ; ++i )
 +  for (v = 0 ; v < n_dep_var ; ++v )
      {
 -      const int row = heading_rows + i * n_stat_rows * n_factors ;
 -
 -      if ( i > 0 )
 -	tab_hline (tbl, TAL_1, 0, n_cols - 1, row );
 +      struct ll *ll;
 +      int i = 0;
 +      const int row_var_start = v * cmd.st_n * 2 * ll_count(&fctr->result_list);
  
 -      tab_text (tbl, 0,
 -		i * n_stat_rows * n_factors  + heading_rows,
 +      tab_text (tbl,
 +		0,
 +		heading_rows + row_var_start,
  		TAB_LEFT | TAT_TITLE,
 -		var_to_string (dependent_var[i])
 +		var_to_string (dependent_var[v])
  		);
  
 -
 -      if ( fctr  )
 +      for (ll = ll_head (&fctr->result_list);
 +	   ll != ll_null (&fctr->result_list); i++, ll = ll_next (ll))
  	{
 -	  const union value *prev = NULL;
 +	  int e ;
 +	  struct ll *min_ll;
 +	  struct ll *max_ll;
 +	  const int row_result_start = i * cmd.st_n * 2;
  
 -	  struct factor_statistics **fs = fctr->fs;
 -	  int count = 0;
 +	  const struct factor_result *result =
 +	    ll_data (ll, struct factor_result, ll);
  
 -	  tab_text (tbl, 1, heading_rows - 1, TAB_CENTER | TAT_TITLE,
 -		    var_to_string (fctr->indep_var[0]));
 +	  if (i > 0 || v > 0)
 +	    tab_hline (tbl, TAL_1, 1, n_cols - 1,
 +		       heading_rows + row_var_start + row_result_start);
  
 +	  tab_hline (tbl, TAL_1, heading_columns - 2, n_cols - 1,
 +		     heading_rows + row_var_start + row_result_start + cmd.st_n);
  
 -	  if ( fctr->indep_var[1])
 -	    tab_text (tbl, 2, heading_rows - 1, TAB_CENTER | TAT_TITLE,
 -		      var_to_string (fctr->indep_var[1]));
 -
 -	  while ( *fs )
 +	  for ( e = 1; e <= cmd.st_n; ++e )
  	    {
 -	      const int row = heading_rows + n_stat_rows  *
 -		 ( ( i  * n_factors  ) +  count );
 -
 -
 -	      if ( !prev || 0 != compare_values (prev, (*fs)->id[0],
 -                                        var_get_width (fctr->indep_var[0])))
 -		{
 -		  struct string vstr;
 -		  ds_init_empty (&vstr);
 -		  var_append_value_name (fctr->indep_var[0],
 -				      (*fs)->id[0], &vstr);
 +	      tab_text_format (tbl, n_cols - 3,
 +                               heading_rows + row_var_start + row_result_start + e - 1,
 +                               TAB_RIGHT,
 +                               "%d", e);
 +
 +	      tab_text_format (tbl, n_cols - 3,
 +                               heading_rows + row_var_start + row_result_start + cmd.st_n + e - 1,
 +                               TAB_RIGHT,
 +                               "%d", e);
 +	    }
  
 -		  if ( count > 0 )
 -		    tab_hline (tbl, TAL_1, 1, n_cols - 1, row);
  
 -		  tab_text (tbl,
 -			    1, row,
 -			    TAB_LEFT | TAT_TITLE,
 -			    ds_cstr (&vstr)
 -			    );
 +	  min_ll = ll_head (extrema_list (result->metrics[v].minima));
 +	  for (e = 0; e < cmd.st_n;)
 +	    {
 +	      struct extremum *minimum = ll_data (min_ll, struct extremum, ll);
 +	      double weight = minimum->weight;
  
 -		  ds_destroy (&vstr);
 +	      while (weight-- > 0 && e < cmd.st_n)
 +		{
 +		  tab_double (tbl, n_cols - 1,
 +			     heading_rows + row_var_start + row_result_start + cmd.st_n + e,
 +			     TAB_RIGHT,
 +			     minimum->value,
 +			     NULL);
 +
 +
 +		  tab_fixed (tbl, n_cols - 2,
 +			     heading_rows + row_var_start +
 +			     row_result_start + cmd.st_n + e,
 +			     TAB_RIGHT,
 +			     minimum->location,
 +			     10, 0);
 +		  ++e;
  		}
  
 -	      prev = (*fs)->id[0];
 +	      min_ll = ll_next (min_ll);
 +	    }
  
- 
 -	      if (fctr->indep_var[1] && count > 0 )
 -		tab_hline (tbl, TAL_1, 2, n_cols - 1, row);
 +	  max_ll = ll_head (extrema_list (result->metrics[v].maxima));
 +	  for (e = 0; e < cmd.st_n;)
 +	    {
 +	      struct extremum *maximum = ll_data (max_ll, struct extremum, ll);
 +	      double weight = maximum->weight;
  
 -	      if ( fctr->indep_var[1])
 +	      while (weight-- > 0 && e < cmd.st_n)
  		{
 -		  struct string vstr;
 -		  ds_init_empty (&vstr);
 -		  var_append_value_name (fctr->indep_var[1], (*fs)->id[1], &vstr);
 -
 -		tab_text (tbl, 2, row,
 -			  TAB_LEFT | TAT_TITLE,
 -			    ds_cstr (&vstr)
 -			  );
 -
 -		  ds_destroy (&vstr);
 +		  tab_double (tbl, n_cols - 1,
 +			     heading_rows + row_var_start +
 +			      row_result_start + e,
 +			     TAB_RIGHT,
 +			     maximum->value,
 +			     NULL);
 +
 +
 +		  tab_fixed (tbl, n_cols - 2,
 +			     heading_rows + row_var_start +
 +			     row_result_start + e,
 +			     TAB_RIGHT,
 +			     maximum->location,
 +			     10, 0);
 +		  ++e;
  		}
  
 -	      populate_descriptives (tbl, heading_columns - 2,
 -				     row,
 -				     dependent_var[i],
 -				     & (*fs)->m[i]);
 -
 -	      count++ ;
 -	      fs++;
 +	      max_ll = ll_next (max_ll);
  	    }
  
 -	}
 -
 -      else
 -	{
 -
 -	  populate_descriptives (tbl, heading_columns - 2,
 -				 i * n_stat_rows * n_factors  + heading_rows,
 -				 dependent_var[i],
 -				 &totals[i]);
 -	}
 -    }
 -
 -  tab_submit (tbl);
 -}
 -
 -
 -/* Fill in the descriptives data */
 -static void
 -populate_descriptives (struct tab_table *tbl, int col, int row,
 -		       const struct variable *var,
 -		       const struct metrics *m)
 -{
 -  const double t = gsl_cdf_tdist_Qinv ((1 - cmd.n_cinterval[0] / 100.0)/2.0,
 -				       m->n -1);
 -
 -  tab_text (tbl, col,
 -	    row,
 -	    TAB_LEFT | TAT_TITLE,
 -	    _ ("Mean"));
 -
 -  tab_double (tbl, col + 2,
 -	      row,
 -	      TAB_CENTER,
 -	      m->mean,
 -	      NULL);
 -
 -  tab_double (tbl, col + 3,
 -	      row,
 -	      TAB_CENTER,
 -	      m->se_mean,
 -	      NULL);
 -
 -
 -  tab_text (tbl, col,
 -	    row + 1,
 -	    TAB_LEFT | TAT_TITLE | TAT_PRINTF,
 -	    _ ("%g%% Confidence Interval for Mean"), cmd.n_cinterval[0]);
 -
 -
 -  tab_text (tbl, col + 1,
 -	    row  + 1,
 -	    TAB_LEFT | TAT_TITLE,
 -	    _ ("Lower Bound"));
 -
 -  tab_double (tbl, col + 2,
 -	      row + 1,
 -	      TAB_CENTER,
 -	      m->mean - t * m->se_mean,
 -	      NULL);
 -
 -  tab_text (tbl, col + 1,
 -	    row + 2,
 -	    TAB_LEFT | TAT_TITLE,
 -	    _ ("Upper Bound"));
 -
 -
 -  tab_double (tbl, col + 2,
 -	      row + 2,
 -	      TAB_CENTER,
 -	      m->mean + t * m->se_mean,
 -	      NULL);
 -
 -  tab_text (tbl, col,
 -	    row + 3,
 -	    TAB_LEFT | TAT_TITLE | TAT_PRINTF,
 -	    _ ("5%% Trimmed Mean"));
 -
 -  tab_double (tbl, col + 2,
 -	      row + 3,
 -	      TAB_CENTER,
 -	      m->trimmed_mean,
 -	      NULL);
 -
 -  tab_text (tbl, col,
 -	    row + 4,
 -	    TAB_LEFT | TAT_TITLE,
 -	    _ ("Median"));
 -
 -  {
 -    struct percentile *p;
 -    double d = 50;
 -
 -    p = hsh_find (m->ptile_hash, &d);
 -
 -    assert (p);
 -
 -
 -    tab_double (tbl, col + 2,
 -		row + 4,
 -		TAB_CENTER,
 -		p->v,
 -		NULL);
 -  }
 -
 -
 -  tab_text (tbl, col,
 -	    row + 5,
 -	    TAB_LEFT | TAT_TITLE,
 -	    _ ("Variance"));
 -
 -  tab_double (tbl, col + 2,
 -	      row + 5,
 -	      TAB_CENTER,
 -	      m->var,
 -	      NULL);
 -
 -
 -  tab_text (tbl, col,
 -	    row + 6,
 -	    TAB_LEFT | TAT_TITLE,
 -	    _ ("Std. Deviation"));
 -
 -
 -  tab_double (tbl, col + 2,
 -	      row + 6,
 -	      TAB_CENTER,
 -	      m->stddev,
 -	      NULL);
 -
 -
 -  tab_text (tbl, col,
 -	    row + 7,
 -	    TAB_LEFT | TAT_TITLE,
 -	    _ ("Minimum"));
 -
 -  tab_double (tbl, col + 2,
 -	      row + 7,
 -	      TAB_CENTER,
 -	      m->min, var_get_print_format (var));
 -
 -  tab_text (tbl, col,
 -	    row + 8,
 -	    TAB_LEFT | TAT_TITLE,
 -	    _ ("Maximum"));
 -
 -  tab_double (tbl, col + 2,
 -	      row + 8,
 -	      TAB_CENTER,
 -	      m->max, var_get_print_format (var));
 -
 -  tab_text (tbl, col,
 -	    row + 9,
 -	    TAB_LEFT | TAT_TITLE,
 -	    _ ("Range"));
 -
 -
 -  tab_double (tbl, col + 2,
 -	      row + 9,
 -	      TAB_CENTER,
 -	      m->max - m->min,
 -	      NULL);
 -
 -  tab_text (tbl, col,
 -	    row + 10,
 -	    TAB_LEFT | TAT_TITLE,
 -	    _ ("Interquartile Range"));
 -
 -  {
 -    struct percentile *p1;
 -    struct percentile *p2;
 -
 -    double d = 75;
 -    p1 = hsh_find (m->ptile_hash, &d);
 -
 -    d = 25;
 -    p2 = hsh_find (m->ptile_hash, &d);
 -
 -    assert (p1);
 -    assert (p2);
 -
 -    tab_double (tbl, col + 2,
 -		row + 10,
 -		TAB_CENTER,
 -		p1->v - p2->v,
 -		NULL);
 -  }
 -
 -  tab_text (tbl, col,
 -	    row + 11,
 -	    TAB_LEFT | TAT_TITLE,
 -	    _ ("Skewness"));
 -
 -
 -  tab_double (tbl, col + 2,
 -	      row + 11,
 -	      TAB_CENTER,
 -	      m->skewness,
 -	      NULL);
 -
 -  /* stderr of skewness */
 -  tab_double (tbl, col + 3,
 -	      row + 11,
 -	      TAB_CENTER,
 -	      calc_seskew (m->n),
 -	      NULL);
 -
 -  tab_text (tbl, col,
 -	    row + 12,
 -	    TAB_LEFT | TAT_TITLE,
 -	    _ ("Kurtosis"));
 -
 -
 -  tab_double (tbl, col + 2,
 -	      row + 12,
 -	      TAB_CENTER,
 -	      m->kurtosis,
 -	      NULL);
 -
 -  /* stderr of kurtosis */
 -  tab_double (tbl, col + 3,
 -	      row + 12,
 -	      TAB_CENTER,
 -	      calc_sekurt (m->n),
 -	      NULL);
 -}
 -
 -
 -
 -void
 -box_plot_variables (const struct factor *fctr,
 -		   const struct variable **vars, int n_vars,
 -		   const struct variable *id)
 -{
 -
 -  int i;
 -  struct factor_statistics **fs ;
 -
 -  if ( ! fctr )
 -    {
 -      box_plot_group (fctr, vars, n_vars, id);
 -      return;
 -    }
 -
 -  for ( fs = fctr->fs ; *fs ; ++fs )
 -    {
 -      struct string str;
 -      double y_min = DBL_MAX;
 -      double y_max = -DBL_MAX;
 -      struct chart *ch = chart_create ();
 -      if (ch == NULL)
 -        break;
 -
 -      ds_init_empty (&str);
 -      factor_to_string (fctr, *fs, 0, &str );
 -
 -      chart_write_title (ch, "%s", ds_cstr (&str));
 -
 -      for ( i = 0 ; i < n_vars ; ++i )
 -	{
 -	  y_max = MAX (y_max, (*fs)->m[i].max);
 -	  y_min = MIN (y_min, (*fs)->m[i].min);
 -	}
 -
 -      boxplot_draw_yscale (ch, y_max, y_min);
 -
 -      for ( i = 0 ; i < n_vars ; ++i )
 -	{
 -
 -	  const double box_width = (ch->data_right - ch->data_left)
 -	    / (n_vars * 2.0 ) ;
 -
 -	  const double box_centre = ( i * 2 + 1) * box_width
 -	    + ch->data_left;
 -
 -	  boxplot_draw_boxplot (ch,
 -			       box_centre, box_width,
 -			       & (*fs)->m[i],
 -			       var_to_string (vars[i]));
  
 -
 -	}
 -
 -      chart_submit (ch);
 -      ds_destroy (&str);
 -    }
 -}
 -
 -
 -
 -/* Do a box plot, grouping all factors into one plot ;
 -   each dependent variable has its own plot.
 -*/
 -void
 -box_plot_group (const struct factor *fctr,
 -	       const struct variable **vars,
 -	       int n_vars,
 -	       const struct variable *id UNUSED)
 -{
 -
 -  int i;
 -
 -  for ( i = 0 ; i < n_vars ; ++i )
 -    {
 -      struct factor_statistics **fs ;
 -      struct chart *ch;
 -
 -      ch = chart_create ();
 -      if (ch == NULL)
 -        break;
 -
 -      boxplot_draw_yscale (ch, totals[i].max, totals[i].min);
 -
 -      if ( fctr )
 -	{
 -	  int n_factors = 0;
 -	  int f=0;
 -	  for ( fs = fctr->fs ; *fs ; ++fs )
 -	    ++n_factors;
 -
 -	  chart_write_title (ch, _ ("Boxplot of %s vs. %s"),
 -			    var_to_string (vars[i]), var_to_string (fctr->indep_var[0]) );
 -
 -	  for ( fs = fctr->fs ; *fs ; ++fs )
 +	  if ( fctr->indep_var[0])
  	    {
 -	      struct string str;
 -	      const double box_width = (ch->data_right - ch->data_left)
 -		/ (n_factors * 2.0 ) ;
 -
 -	      const double box_centre = ( f++ * 2 + 1) * box_width
 -		+ ch->data_left;
 -
 -	      ds_init_empty (&str);
 -	      factor_to_string_concise (fctr, *fs, &str);
 +	      struct string vstr;
 +	      ds_init_empty (&vstr);
 +	      var_append_value_name (fctr->indep_var[0],
 +				     &result->value[0], &vstr);
 +
 +	      tab_text (tbl, 1,
 +			heading_rows + row_var_start + row_result_start,
 +			TAB_LEFT,
 +			ds_cstr (&vstr)
 +			);
  
 -	      boxplot_draw_boxplot (ch,
 -				   box_centre, box_width,
 -				   & (*fs)->m[i],
 -				   ds_cstr (&str));
 -              ds_destroy (&str);
 +	      ds_destroy (&vstr);
  	    }
 -	}
 -      else if ( ch )
 -	{
 -	  const double box_width = (ch->data_right - ch->data_left) / 3.0;
 -	  const double box_centre = (ch->data_right + ch->data_left) / 2.0;
  
 -	  chart_write_title (ch, _ ("Boxplot"));
  
 -	  boxplot_draw_boxplot (ch,
 -			       box_centre,    box_width,
 -			       &totals[i],
 -			       var_to_string (vars[i]) );
 +	  tab_text (tbl, n_cols - 4,
 +		    heading_rows + row_var_start + row_result_start,
 +		    TAB_RIGHT,
 +		    _("Highest"));
  
 +	  tab_text (tbl, n_cols - 4,
 +		    heading_rows + row_var_start + row_result_start + cmd.st_n,
 +		    TAB_RIGHT,
 +		    _("Lowest"));
  	}
 -
 -      chart_submit (ch);
      }
 -}
 -
 -
 -/* Plot the normal and detrended normal plots for m
 -   Label the plots with factorname */
 -void
 -np_plot (const struct metrics *m, const char *factorname)
 -{
 -  int i;
 -  double yfirst=0, ylast=0;
 -
 -  /* 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 / m->stddev;
 -  const double intercept = - m->mean / m->stddev;
 -
 -  /* Cowardly refuse to plot an empty data set */
 -  if ( m->n_data == 0 )
 -    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"), factorname);
 -  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"),
 -		    factorname);
 -  chart_write_xlabel (dnp_chart, _ ("Observed Value"));
 -  chart_write_ylabel (dnp_chart, _ ("Dev from Normal"));
 -
 -  yfirst = gsl_cdf_ugaussian_Pinv (m->wvp[0]->rank / ( m->n + 1));
 -  ylast =  gsl_cdf_ugaussian_Pinv (m->wvp[m->n_data-1]->rank / ( m->n + 1));
 -
 -
 -  {
 -    /* Need to make sure that both the scatter plot and the ideal fit into the
 -       plot */
 -    double x_lower = MIN (m->min, (yfirst - intercept) / slope) ;
 -    double x_upper = MAX (m->max, (ylast  - intercept) / slope) ;
 -    double slack = (x_upper - x_lower)  * 0.05 ;
 -
 -    chart_write_xscale (np_chart, x_lower - slack, x_upper + slack, 5);
 -
 -    chart_write_xscale (dnp_chart, m->min, m->max, 5);
 -
 -  }
  
 -  chart_write_yscale (np_chart, yfirst, ylast, 5);
 -
 -  {
 -    /* We have to cache the detrended data, beacause we need to
 -       find its limits before we can plot it */
 -    double *d_data = xnmalloc (m->n_data, sizeof *d_data);
 -    double d_max = -DBL_MAX;
 -    double d_min = DBL_MAX;
 -    for ( i = 0 ; i < m->n_data; ++i )
 -      {
 -	const double ns = gsl_cdf_ugaussian_Pinv (m->wvp[i]->rank / ( m->n + 1));
 +  tab_vline (tbl, TAL_2, heading_columns, 0, n_rows - 1);
  
 -	chart_datum (np_chart, 0, m->wvp[i]->v.f, ns);
  
 -	d_data[i] = (m->wvp[i]->v.f - m->mean) / m->stddev  - ns;
 +  tab_title (tbl, _("Extreme Values"));
  
 -	if ( d_data[i] < d_min ) d_min = d_data[i];
 -	if ( d_data[i] > d_max ) d_max = d_data[i];
 -      }
 -    chart_write_yscale (dnp_chart, d_min, d_max, 5);
  
 -    for ( i = 0 ; i < m->n_data; ++i )
 -      chart_datum (dnp_chart, 0, m->wvp[i]->v.f, d_data[i]);
 +  tab_text (tbl, n_cols - 2, 0, TAB_CENTER | TAT_TITLE,
 +	    _("Case Number"));
  
 -    free (d_data);
 -  }
  
 -  chart_line (np_chart, slope, intercept, yfirst, ylast , CHART_DIM_Y);
 -  chart_line (dnp_chart, 0, 0, m->min, m->max , CHART_DIM_X);
 +  tab_text (tbl, n_cols - 1, 0, TAB_CENTER | TAT_TITLE,
 +	    _("Value"));
  
 -  chart_submit (np_chart);
 -  chart_submit (dnp_chart);
 +  tab_submit (tbl);
  }
  
 +#define PERCENTILE_ROWS 2
  
 -
 -
 -/* Show the percentiles */
 -void
 +static void
  show_percentiles (const struct variable **dependent_var,
 -		 int n_dep_var,
 -		 struct factor *fctr)
 +		  int n_dep_var,
 +		  const struct xfactor *fctr)
  {
 -  struct tab_table *tbl;
    int i;
 +  int v;
 +  int heading_columns = 2;
 +  int n_cols;
 +  const int n_percentiles = subc_list_double_count (&percentile_list);
 +  const int heading_rows = 2;
 +  struct tab_table *tbl;
  
 -  int n_cols, n_rows;
 -  int n_factors;
 -
 -  struct hsh_table *ptiles ;
 -
 -  int n_heading_columns;
 -  const int n_heading_rows = 2;
 -  const int n_stat_rows = 2;
 +  int n_rows ;
 +  n_rows = n_dep_var;
  
 -  int n_ptiles ;
 +  assert (fctr);
  
 -  if ( fctr )
 +  if ( fctr->indep_var[0] )
      {
 -      struct factor_statistics **fs = fctr->fs ;
 -      n_heading_columns = 3;
 -      n_factors = hsh_count (fctr->fstats);
 -
 -      ptiles = (*fs)->m[0].ptile_hash;
 +      heading_columns = 3;
  
        if ( fctr->indep_var[1] )
 -	n_heading_columns = 4;
 -    }
 -  else
 -    {
 -      n_factors = 1;
 -      n_heading_columns = 2;
 -
 -      ptiles = totals[0].ptile_hash;
 +	{
 +	  heading_columns = 4;
 +	}
      }
  
 -  n_ptiles = hsh_count (ptiles);
 -
 -  n_rows = n_heading_rows + n_dep_var * n_stat_rows * n_factors;
 +  n_rows *= ll_count (&fctr->result_list) * PERCENTILE_ROWS;
 +  n_rows += heading_rows;
  
 -  n_cols = n_heading_columns + n_ptiles ;
 +  n_cols = heading_columns + n_percentiles;
  
    tbl = tab_create (n_cols, n_rows, 0);
 +  tab_headers (tbl, heading_columns, 0, heading_rows, 0);
  
 -  tab_headers (tbl, n_heading_columns + 1, 0, n_heading_rows, 0);
 -
 -  tab_dim (tbl, tab_natural_dimensions);
 +  tab_dim (tbl, tab_natural_dimensions, NULL);
  
 -  /* Outline the box and have no internal lines*/
 +  /* Outline the box */
    tab_box (tbl,
  	   TAL_2, TAL_2,
  	   -1, -1,
diff --cc src/language/stats/t-test.q
index d25477cdd1,ba7e9388a9..c448d52ea0
--- a/src/language/stats/t-test.q
+++ b/src/language/stats/t-test.q
@@@ -47,8 -45,7 +47,9 @@@
  #include <output/table.h>
  #include <data/format.h>
  
++#include "minmax.h"
  #include "xalloc.h"
 +#include "xmemdup0.h"
  
  #include "gettext.h"
  #define _(msgid) gettext (msgid)
@@@ -1091,40 -1411,49 +1092,44 @@@ pscbox (struct t_test_proc *proc
  
    struct tab_table *table;
  
 -  table = tab_create (cols,rows,0);
 +  table = tab_create (cols, rows, 0);
  
    tab_columns (table, SOM_COL_DOWN, 1);
 -  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_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);
 -  tab_title (table, _ ("Paired Samples Correlations"));
 +  tab_dim (table, tab_natural_dimensions, NULL);
 +  tab_title (table, _("Paired Samples Correlations"));
  
    /* column headings */
 -  tab_text (table, 2,0, TAB_CENTER | TAT_TITLE, _ ("N"));
 -  tab_text (table, 3,0, TAB_CENTER | TAT_TITLE, _ ("Correlation"));
 -  tab_text (table, 4,0, TAB_CENTER | TAT_TITLE, _ ("Sig."));
 +  tab_text (table, 2, 0, TAB_CENTER | TAT_TITLE, _("N"));
 +  tab_text (table, 3, 0, TAB_CENTER | TAT_TITLE, _("Correlation"));
 +  tab_text (table, 4, 0, TAB_CENTER | TAT_TITLE, _("Sig."));
  
 -  for (i=0; i < n_pairs; ++i)
 +  for (i = 0; i < proc->n_pairs; i++)
      {
 -      double p,q;
 -
 -      double df = pairs[i].n -2;
 +      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 (pairs[i].correlation));
 -      double correlation_t =
 -	pairs[i].correlation * sqrt (df) /
 -	sqrt (1 - corr2);
 -
++      double corr2 = MIN (1.0, pow2 (pair->correlation));
++      double correlation_t = pair->correlation * sqrt (df) / sqrt (1 - corr2);
  
        /* row headings */
 -      tab_text (table, 0,i+1, TAB_LEFT | TAT_TITLE | TAT_PRINTF,
 -	       _ ("Pair %d"), i);
 -
 -      tab_text (table, 1,i+1, TAB_LEFT | TAT_TITLE | TAT_PRINTF,
 -	       _ ("%s & %s"),
 -               var_get_name (pairs[i].v[0]),
 -               var_get_name (pairs[i].v[1]));
 -
 +      tab_text_format (table, 0, i + 1, TAB_LEFT | TAT_TITLE,
 +                       _("Pair %d"), i);
 +      tab_text_format (table, 1, i + 1, TAB_LEFT | TAT_TITLE,
 +                       _("%s & %s"),
 +                       var_get_name (pair->v[0]),
 +                       var_get_name (pair->v[1]));
  
        /* row data */
 -      tab_double (table, 2, i+1, TAB_RIGHT, pairs[i].n, wfmt);
 -      tab_double (table, 3, i+1, TAB_RIGHT, pairs[i].correlation, NULL);
 +      tab_double (table, 2, i + 1, TAB_RIGHT, pair->n, &proc->weight_format);
 +      tab_double (table, 3, i + 1, TAB_RIGHT, pair->correlation, NULL);
  
        p = gsl_cdf_tdist_P (correlation_t, df);
        q = gsl_cdf_tdist_Q (correlation_t, df);
diff --cc src/output/charts/box-whisker.c
index c3641580e0,8bcad4947e..33c445b09a
--- a/src/output/charts/box-whisker.c
+++ b/src/output/charts/box-whisker.c
@@@ -1,5 -1,5 +1,5 @@@
  /* PSPP - a program for statistical analysis.
-    Copyright (C) 2004, 2008 Free Software Foundation, Inc.
 -   Copyright (C) 2004, 2009 Free Software Foundation, Inc.
++   Copyright (C) 2004, 2008, 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
@@@ -134,26 -182,37 +134,26 @@@ boxplot_draw_boxplot (struct chart *ch
  	     box_centre, box_bottom);
  
    /* (top half) */
 -  pl_fline_r(ch->lp,
 +  pl_fline_r (ch->lp,
  	     box_centre, top_whisker,
  	     box_centre, box_top);
 -  }
  
 -  /* Draw outliers */
 -  for ( i = 0 ; i < n_data ; ++i )
 +  outliers = box_whisker_outliers (bw);
 +  for (ll = ll_head (outliers);
 +       ll != ll_null (outliers); ll = ll_next (ll))
      {
 -      if ( wvp[i]->v.f >= hinge[2] + step )
 -	draw_outlier(ch, box_centre, wvp, i,
 -		     ( wvp[i]->v.f > hinge[2] + 2 * step )
 -		     );
 -
 -      if ( wvp[i]->v.f <= hinge[0] - step )
 -	draw_outlier(ch, box_centre, wvp, i,
 -		     ( wvp[i]->v.f < hinge[0] - 2 * step )
 -		     );
 +      const struct outlier *outlier = ll_data (ll, struct outlier, ll);
 +      draw_case (ch, box_centre, outlier);
      }
  
 -
    /* Draw  tick  mark on x axis */
-   draw_tick(ch, TICK_ABSCISSA, box_centre - ch->data_left, name);
+   draw_tick(ch, TICK_ABSCISSA, box_centre - ch->data_left, "%s", name);
  
    pl_restorestate_r(ch->lp);
 -
  }
  
 -
 -
  void
 -boxplot_draw_yscale(struct chart *ch , double y_max, double y_min)
 +boxplot_draw_yscale (struct chart *ch, double y_max, double y_min)
  {
    double y_tick;
    double d;
diff --cc src/output/charts/plot-hist.c
index 4b11618a2f,88ad089919..fbf1925e63
--- a/src/output/charts/plot-hist.c
+++ b/src/output/charts/plot-hist.c
@@@ -97,14 -96,10 +97,10 @@@ hist_draw_bar (struct chart *ch, const 
  		 x_pos, 0,
  		 x_pos + width, height);
  
 -    pl_restorestate_r(ch->lp);
 +    pl_restorestate_r (ch->lp);
  
-     {
-       char buf[5];
-       snprintf (buf,5,"%g", (upper + lower) / 2.0);
-       draw_tick (ch, TICK_ABSCISSA,
- 		x_pos + width / 2.0, buf);
-     }
+     draw_tick (ch, TICK_ABSCISSA,
+                x_pos + width / 2.0, "%g", (upper + lower) / 2.0);
    }
  }
  
diff --cc src/ui/gui/psppire.c
index 3555463f88,a7b22037b8..1cd7ee803c
--- a/src/ui/gui/psppire.c
+++ b/src/ui/gui/psppire.c
@@@ -89,10 -75,14 +89,9 @@@ initialize (struct command_line_process
  {
    PsppireDict *dictionary = 0;
  
 -  /* gtk_init messes with the locale.
 -     So unset the bits we want to control ourselves */
 -  setlocale (LC_NUMERIC, "C");
 -
 -  bindtextdomain (PACKAGE, relocate (locale_dir));
--
 +  i18n_init ();
  
 -  glade_init ();
 +  preregister_widgets ();
  
    gsl_set_error_handler_off ();
    fn_init ();
diff --cc src/ui/gui/psppire.h
index cfe49e9182,815de4a07e..27a633f2ec
--- a/src/ui/gui/psppire.h
+++ b/src/ui/gui/psppire.h
@@@ -17,16 -17,9 +17,16 @@@
  #ifndef PSPPIRE_H
  #define PSPPIRE_H
  
 +#include <argp.h>
  
 -void initialize (void);
 +struct command_line_processor ;
 +extern const struct argp non_option_argp ;
 +
 +void initialize (struct command_line_processor *, int argc, char **argv);
  void de_initialize (void);
++
 +void psppire_quit (void);
 +
  const char * output_file_name (void);
  
- 
  #endif /* PSPPIRE_H */
diff --cc src/ui/terminal/main.c
index af8f7f2dd4,8acbdc2dde..7ad162fca6
--- a/src/ui/terminal/main.c
+++ b/src/ui/terminal/main.c
@@@ -166,6 -141,21 +167,7 @@@ main (int argc, char **argv
    return any_errors ();
  }
  
 -static void
 -i18n_init (void)
 -{
 -#if ENABLE_NLS
 -#if HAVE_LC_MESSAGES
 -  setlocale (LC_MESSAGES, "");
 -#endif
 -#if HAVE_LC_PAPER
 -  setlocale (LC_PAPER, "");
 -#endif
 -  bindtextdomain (PACKAGE, relocate (locale_dir));
 -  textdomain (PACKAGE);
 -#endif /* ENABLE_NLS */
 -}
+ 
  static void
  fpu_init (void)
  {