output: Add auxiliary data parameter to tab_dim.
[pspp-builds.git] / src / language / stats / crosstabs.q
index 4d8a2b7bdd6fdfb29d3cd8622cf64a8943f17929..b71524a11a41175d132ea56978d6a1e4d7ff9400 100644 (file)
@@ -1,20 +1,18 @@
-/* PSPP - computes sample statistics.
-   Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 1997-9, 2000, 2006, 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 2 of the
-   License, or (at your option) any later version.
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
 
-   This program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA. */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 /* FIXME:
 
@@ -36,6 +34,8 @@
 #include <stdio.h>
 
 #include <data/case.h>
+#include <data/casegrouper.h>
+#include <data/casereader.h>
 #include <data/data-out.h>
 #include <data/dictionary.h>
 #include <data/format.h>
 #include <language/dictionary/split-file.h>
 #include <language/lexer/lexer.h>
 #include <language/lexer/variable-parser.h>
-#include <libpspp/alloc.h>
 #include <libpspp/array.h>
 #include <libpspp/assertion.h>
 #include <libpspp/compiler.h>
 #include <libpspp/hash.h>
-#include <libpspp/magic.h>
-#include <libpspp/message.h>
 #include <libpspp/message.h>
 #include <libpspp/misc.h>
 #include <libpspp/pool.h>
@@ -61,6 +58,8 @@
 #include <output/table.h>
 
 #include "minmax.h"
+#include "xalloc.h"
+#include "xmalloca.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -116,7 +115,7 @@ struct crosstab
     int nvar;                  /* Number of variables. */
     double missing;            /* Missing cases count. */
     int ofs;                   /* Integer mode: Offset into sorted_tab[]. */
-    struct variable *vars[2];  /* At least two variables; sorted by
+    const struct variable *vars[2];    /* At least two variables; sorted by
                                   larger indices first. */
   };
 
@@ -129,7 +128,7 @@ struct var_range
   };
 
 static inline struct var_range *
-get_var_range (struct variable *v) 
+get_var_range (const struct variable *v)
 {
   return var_get_aux (v);
 }
@@ -147,7 +146,7 @@ static int n_sorted_tab;            /* Number of entries in sorted_tab. */
 static struct table_entry **sorted_tab;        /* Sorted table. */
 
 /* Variables specifies on VARIABLES. */
-static struct variable **variables;
+static const struct variable **variables;
 static size_t variables_cnt;
 
 /* TABLES. */
@@ -177,10 +176,11 @@ static struct pool *pl_tc;        /* For table cells. */
 static struct pool *pl_col;    /* For column data. */
 
 static int internal_cmd_crosstabs (struct lexer *lexer, struct dataset *ds);
-static void precalc (const struct ccase *, void *, const struct dataset *);
-static bool calc_general (const struct ccase *, void *, const struct dataset *);
-static bool calc_integer (const struct ccase *, void *, const struct dataset *);
-static bool postcalc (void *, const struct dataset *);
+static void precalc (struct casereader *, const struct dataset *);
+static void calc_general (const struct ccase *, const struct dataset *);
+static void calc_integer (const struct ccase *, const struct dataset *);
+static void postcalc (const struct dataset *);
+
 static void submit (struct tab_table *);
 
 static void format_short (char *s, const struct fmt_spec *fp,
@@ -191,11 +191,16 @@ int
 cmd_crosstabs (struct lexer *lexer, struct dataset *ds)
 {
   int result = internal_cmd_crosstabs (lexer, ds);
+  int i;
 
   free (variables);
   pool_destroy (pl_tc);
   pool_destroy (pl_col);
-  
+
+  for (i = 0; i < nxtab; i++)
+    free (xtab[i]);
+  free (xtab);
+
   return result;
 }
 
@@ -203,8 +208,10 @@ cmd_crosstabs (struct lexer *lexer, struct dataset *ds)
 static int
 internal_cmd_crosstabs (struct lexer *lexer, struct dataset *ds)
 {
-  int i;
+  struct casegrouper *grouper;
+  struct casereader *input, *group;
   bool ok;
+  int i;
 
   variables = NULL;
   variables_cnt = 0;
@@ -223,7 +230,7 @@ internal_cmd_crosstabs (struct lexer *lexer, struct dataset *ds)
     {
       cmd.a_cells[CRS_CL_COUNT] = 1;
     }
-  else 
+  else
     {
       int count = 0;
 
@@ -264,7 +271,7 @@ internal_cmd_crosstabs (struct lexer *lexer, struct dataset *ds)
        for (i = 0; i < CRS_ST_count; i++)
          cmd.a_statistics[i] = 1;
     }
-  
+
   /* MISSING. */
   if (cmd.miss == CRS_REPORT && mode == GENERAL)
     {
@@ -294,9 +301,28 @@ internal_cmd_crosstabs (struct lexer *lexer, struct dataset *ds)
   else
     write_style = CRS_WR_NONE;
 
-  ok = procedure_with_splits (ds, precalc,
-                              mode == GENERAL ? calc_general : calc_integer,
-                              postcalc, NULL);
+  input = casereader_create_filter_weight (proc_open (ds), dataset_dict (ds),
+                                           NULL, NULL);
+  grouper = casegrouper_create_splits (input, dataset_dict (ds));
+  while (casegrouper_get_next_group (grouper, &group))
+    {
+      struct ccase *c;
+
+      precalc (group, ds);
+
+      for (; (c = casereader_read (group)) != NULL; case_unref (c))
+        {
+          if (mode == GENERAL)
+            calc_general (c, ds);
+          else
+            calc_integer (c, ds);
+        }
+      casereader_destroy (group);
+
+      postcalc (ds);
+    }
+  ok = casegrouper_destroy (grouper);
+  ok = proc_commit (ds) && ok;
 
   return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
 }
@@ -305,36 +331,37 @@ internal_cmd_crosstabs (struct lexer *lexer, struct dataset *ds)
 static int
 crs_custom_tables (struct lexer *lexer, struct dataset *ds, struct cmd_crosstabs *cmd UNUSED, void *aux UNUSED)
 {
-  struct var_set *var_set;
+  struct const_var_set *var_set;
   int n_by;
-  struct variable ***by = NULL;
+  const struct variable ***by = NULL;
   size_t *by_nvar = NULL;
   size_t nx = 1;
   int success = 0;
 
   /* Ensure that this is a TABLES subcommand. */
   if (!lex_match_id (lexer, "TABLES")
-      && (lex_token (lexer) != T_ID || dict_lookup_var (dataset_dict (ds), lex_tokid (lexer)) == NULL)
+      && (lex_token (lexer) != T_ID ||
+         dict_lookup_var (dataset_dict (ds), lex_tokid (lexer)) == NULL)
       && lex_token (lexer) != T_ALL)
     return 2;
   lex_match (lexer, '=');
 
   if (variables != NULL)
-    var_set = var_set_create_from_array (variables, variables_cnt);
+    var_set = const_var_set_create_from_array (variables, variables_cnt);
   else
-    var_set = var_set_create_from_dict (dataset_dict (ds));
+    var_set = const_var_set_create_from_dict (dataset_dict (ds));
   assert (var_set != NULL);
-  
+
   for (n_by = 0; ;)
     {
       by = xnrealloc (by, n_by + 1, sizeof *by);
       by_nvar = xnrealloc (by_nvar, n_by + 1, sizeof *by_nvar);
-      if (!parse_var_set_vars (lexer, var_set, &by[n_by], &by_nvar[n_by],
+      if (!parse_const_var_set_vars (lexer, var_set, &by[n_by], &by_nvar[n_by],
                                PV_NO_DUPLICATE | PV_NO_SCRATCH))
        goto done;
-      if (xalloc_oversized (nx, by_nvar[n_by])) 
+      if (xalloc_oversized (nx, by_nvar[n_by]))
         {
-          msg (SE, _("Too many crosstabulation variables or dimensions."));
+          msg (SE, _("Too many cross-tabulation variables or dimensions."));
           goto done;
         }
       nx *= by_nvar[n_by];
@@ -347,11 +374,11 @@ crs_custom_tables (struct lexer *lexer, struct dataset *ds, struct cmd_crosstabs
              lex_error (lexer, _("expecting BY"));
              goto done;
            }
-         else 
+         else
            break;
        }
     }
-  
+
   {
     int *by_iter = xcalloc (n_by, sizeof *by_iter);
     int i;
@@ -371,7 +398,7 @@ crs_custom_tables (struct lexer *lexer, struct dataset *ds, struct cmd_crosstabs
           for (i = 0; i < n_by; i++)
             x->vars[i] = by[i][by_iter[i]];
        }
-       
+
        {
          int i;
 
@@ -400,7 +427,7 @@ crs_custom_tables (struct lexer *lexer, struct dataset *ds, struct cmd_crosstabs
     free (by_nvar);
   }
 
-  var_set_destroy (var_set);
+  const_var_set_destroy (var_set);
 
   return success;
 }
@@ -416,15 +443,15 @@ crs_custom_variables (struct lexer *lexer, struct dataset *ds, struct cmd_crosst
     }
 
   lex_match (lexer, '=');
-  
+
   for (;;)
     {
       size_t orig_nv = variables_cnt;
       size_t i;
 
       long min, max;
-      
-      if (!parse_variables (lexer, dataset_dict (ds), 
+
+      if (!parse_variables_const (lexer, dataset_dict (ds),
                            &variables, &variables_cnt,
                            (PV_APPEND | PV_NUMERIC
                             | PV_NO_DUPLICATE | PV_NO_SCRATCH)))
@@ -461,8 +488,8 @@ crs_custom_variables (struct lexer *lexer, struct dataset *ds, struct cmd_crosst
          goto lossage;
        }
       lex_get (lexer);
-      
-      for (i = orig_nv; i < variables_cnt; i++) 
+
+      for (i = orig_nv; i < variables_cnt; i++)
         {
           struct var_range *vr = xmalloc (sizeof *vr);
           vr->min = min;
@@ -470,11 +497,11 @@ crs_custom_variables (struct lexer *lexer, struct dataset *ds, struct cmd_crosst
          vr->count = max - min + 1;
           var_attach_aux (variables[i], vr, var_dtor_free);
        }
-      
+
       if (lex_token (lexer) == '/')
        break;
     }
-  
+
   return 1;
 
  lossage:
@@ -489,16 +516,24 @@ static int compare_table_entry (const void *, const void *, const void *);
 static unsigned hash_table_entry (const void *, const void *);
 
 /* Set up the crosstabulation tables for processing. */
-static  void
-precalc (const struct ccase *first, void *aux UNUSED, const struct dataset *ds)
+static void
+precalc (struct casereader *input, const struct dataset *ds)
 {
-  output_split_file_values (ds, first);
+  struct ccase *c;
+
+  c = casereader_peek (input, 0);
+  if (c != NULL)
+    {
+      output_split_file_values (ds, c);
+      case_unref (c);
+    }
+
   if (mode == GENERAL)
     {
       gen_tab = hsh_create (512, compare_table_entry, hash_table_entry,
                            NULL, NULL);
     }
-  else 
+  else
     {
       int i;
 
@@ -514,14 +549,14 @@ precalc (const struct ccase *first, void *aux UNUSED, const struct dataset *ds)
 
          x->ofs = n_sorted_tab;
 
-         for (j = 2; j < x->nvar; j++) 
+         for (j = 2; j < x->nvar; j++)
             count *= get_var_range (x->vars[j - 2])->count;
-          
+
          sorted_tab = xnrealloc (sorted_tab,
                                   n_sorted_tab + count, sizeof *sorted_tab);
-         v = local_alloc (sizeof *v * x->nvar);
-         for (j = 2; j < x->nvar; j++) 
-            v[j] = get_var_range (x->vars[j])->min; 
+         v = xmalloca (sizeof *v * x->nvar);
+         for (j = 2; j < x->nvar; j++)
+            v[j] = get_var_range (x->vars[j])->min;
          for (j = 0; j < count; j++)
            {
              struct table_entry *te;
@@ -530,30 +565,30 @@ precalc (const struct ccase *first, void *aux UNUSED, const struct dataset *ds)
              te = sorted_tab[n_sorted_tab++]
                = xmalloc (sizeof *te + sizeof (union value) * (x->nvar - 1));
              te->table = i;
-             
+
              {
                 int row_cnt = get_var_range (x->vars[0])->count;
                 int col_cnt = get_var_range (x->vars[1])->count;
                const int mat_size = row_cnt * col_cnt;
                int m;
-               
+
                te->u.data = xnmalloc (mat_size, sizeof *te->u.data);
                for (m = 0; m < mat_size; m++)
                  te->u.data[m] = 0.;
              }
-             
+
              for (k = 2; k < x->nvar; k++)
                te->values[k].f = v[k];
-             for (k = 2; k < x->nvar; k++) 
+             for (k = 2; k < x->nvar; k++)
                 {
                   struct var_range *vr = get_var_range (x->vars[k]);
                   if (++v[k] >= vr->max)
                     v[k] = vr->min;
                   else
-                    break; 
+                    break;
                 }
            }
-         local_free (v);
+         freea (v);
        }
 
       sorted_tab = xnrealloc (sorted_tab,
@@ -564,18 +599,16 @@ precalc (const struct ccase *first, void *aux UNUSED, const struct dataset *ds)
 }
 
 /* Form crosstabulations for general mode. */
-static bool
-calc_general (const struct ccase *c, void *aux UNUSED, const struct dataset *ds)
+static void
+calc_general (const struct ccase *c, const struct dataset *ds)
 {
-  bool bad_warn = true;
-
   /* Missing values to exclude. */
   enum mv_class exclude = (cmd.miss == CRS_TABLE ? MV_ANY
                            : cmd.miss == CRS_INCLUDE ? MV_SYSTEM
                            : MV_NEVER);
 
   /* Case weight. */
-  double weight = dict_get_case_weight (dataset_dict (ds), c, &bad_warn);
+  double weight = dict_get_case_weight (dataset_dict (ds), c, NULL);
 
   /* Flattened current table index. */
   int t;
@@ -585,7 +618,7 @@ calc_general (const struct ccase *c, void *aux UNUSED, const struct dataset *ds)
       struct crosstab *x = xtab[t];
       const size_t entry_size = (sizeof (struct table_entry)
                                 + sizeof (union value) * (x->nvar - 1));
-      struct table_entry *te = local_alloc (entry_size);
+      struct table_entry *te = xmalloca (entry_size);
 
       /* Construct table entry for the current record and table. */
       te->table = t;
@@ -601,17 +634,19 @@ calc_general (const struct ccase *c, void *aux UNUSED, const struct dataset *ds)
                x->missing += weight;
                goto next_crosstab;
              }
-             
+
            if (var_is_numeric (x->vars[j]))
              te->values[j].f = case_num (c, x->vars[j]);
            else
              {
-               memcpy (te->values[j].s, case_str (c, x->vars[j]),
-                        var_get_width (x->vars[j]));
-             
+                size_t n = var_get_width (x->vars[j]);
+                if (n > MAX_SHORT_STRING)
+                  n = MAX_SHORT_STRING;
+               memcpy (te->values[j].s, case_str (c, x->vars[j]), n);
+
                /* Necessary in order to simplify comparisons. */
                memset (&te->values[j].s[var_get_width (x->vars[j])], 0,
-                       sizeof (union value) - var_get_width (x->vars[j]));
+                       sizeof (union value) - n);
              }
          }
       }
@@ -623,10 +658,10 @@ calc_general (const struct ccase *c, void *aux UNUSED, const struct dataset *ds)
        if (*tepp == NULL)
          {
            struct table_entry *tep = pool_alloc (pl_tc, entry_size);
-           
+
            te->u.freq = weight;
            memcpy (tep, te, entry_size);
-           
+
            *tepp = tep;
          }
        else
@@ -634,36 +669,34 @@ calc_general (const struct ccase *c, void *aux UNUSED, const struct dataset *ds)
       }
 
     next_crosstab:
-      local_free (te);
+      freea (te);
     }
-  
-  return true;
 }
 
-static bool
-calc_integer (const struct ccase *c, void *aux UNUSED, const struct dataset *ds)
+static void
+calc_integer (const struct ccase *c, const struct dataset *ds)
 {
   bool bad_warn = true;
 
   /* Case weight. */
   double weight = dict_get_case_weight (dataset_dict (ds), c, &bad_warn);
-  
+
   /* Flattened current table index. */
   int t;
-  
+
   for (t = 0; t < nxtab; t++)
     {
       struct crosstab *x = xtab[t];
       int i, fact, ofs;
-      
+
       fact = i = 1;
       ofs = x->ofs;
       for (i = 0; i < x->nvar; i++)
        {
-         struct variable *const v = x->vars[i];
+         const struct variable *const v = x->vars[i];
           struct var_range *vr = get_var_range (v);
          double value = case_num (c, v);
-         
+
          /* Note that the first test also rules out SYSMIS. */
          if ((value < vr->min || value >= vr->max)
              || (cmd.miss == CRS_TABLE
@@ -672,35 +705,33 @@ calc_integer (const struct ccase *c, void *aux UNUSED, const struct dataset *ds)
              x->missing += weight;
              goto next_crosstab;
            }
-         
+
          if (i > 1)
            {
              ofs += fact * ((int) value - vr->min);
              fact *= vr->count;
            }
        }
-      
+
       {
-        struct variable *row_var = x->vars[ROW_VAR];
+        const struct variable *row_var = x->vars[ROW_VAR];
        const int row = case_num (c, row_var) - get_var_range (row_var)->min;
 
-        struct variable *col_var = x->vars[COL_VAR];
+        const struct variable *col_var = x->vars[COL_VAR];
        const int col = case_num (c, col_var) - get_var_range (col_var)->min;
 
        const int col_dim = get_var_range (col_var)->count;
 
        sorted_tab[ofs]->u.data[col + row * col_dim] += weight;
       }
-      
+
     next_crosstab: ;
     }
-  
-  return true;
 }
 
 /* Compare the table_entry's at A and B and return a strcmp()-type
    result. */
-static int 
+static int
 compare_table_entry (const void *a_, const void *b_, const void *aux UNUSED)
 {
   const struct table_entry *a = a_;
@@ -710,7 +741,7 @@ compare_table_entry (const void *a_, const void *b_, const void *aux UNUSED)
     return 1;
   else if (a->table < b->table)
     return -1;
-  
+
   {
     const struct crosstab *x = xtab[a->table];
     int i;
@@ -724,7 +755,7 @@ compare_table_entry (const void *a_, const void *b_, const void *aux UNUSED)
          else if (diffnum > 0)
            return 1;
        }
-      else 
+      else
         {
           const int diffstr = strncmp (a->values[i].s, b->values[i].s,
                                        var_get_width (x->vars[i]));
@@ -732,7 +763,7 @@ compare_table_entry (const void *a_, const void *b_, const void *aux UNUSED)
             return diffstr;
         }
   }
-  
+
   return 0;
 }
 
@@ -746,8 +777,8 @@ hash_table_entry (const void *a_, const void *aux UNUSED)
 
   hash = a->table;
   for (i = 0; i < xtab[a->table]->nvar; i++)
-    hash ^= hsh_hash_bytes (&a->values[i], sizeof a->values[i]);
-  
+    hash = hash_bytes (&a->values[i], sizeof a->values[i], hash);
+
   return hash;
 }
 \f
@@ -759,21 +790,22 @@ static void enum_var_values (struct table_entry **entries, int entry_cnt,
                              int var_idx,
                              union value **values, int *value_cnt);
 static void output_pivot_table (struct table_entry **, struct table_entry **,
+                               const struct dictionary *,
                                double **, double **, double **,
                                int *, int *, int *);
-static void make_summary_table (void);
+static void make_summary_table (const struct dictionary *);
 
-static bool
-postcalc (void *aux UNUSED, const struct dataset *ds UNUSED)
+static void
+postcalc (const struct dataset *ds)
 {
   if (mode == GENERAL)
     {
       n_sorted_tab = hsh_count (gen_tab);
       sorted_tab = (struct table_entry **) hsh_sort (gen_tab);
     }
-  
-  make_summary_table ();
-  
+
+  make_summary_table (dataset_dict (ds));
+
   /* Identify all the individual crosstabulation tables, and deal with
      them. */
   {
@@ -788,30 +820,41 @@ postcalc (void *aux UNUSED, const struct dataset *ds UNUSED)
        pe = find_pivot_extent (pb, &pc, cmd.pivot == CRS_PIVOT);
        if (pe == NULL)
          break;
-       
-       output_pivot_table (pb, pe, &mat, &row_tot, &col_tot,
+
+       output_pivot_table (pb, pe, dataset_dict (ds),
+                           &mat, &row_tot, &col_tot,
                            &maxrows, &maxcols, &maxcells);
-         
+
        pb = pe;
       }
     free (mat);
     free (row_tot);
     free (col_tot);
   }
-  
-  hsh_destroy (gen_tab);
 
-  return true;
+  hsh_destroy (gen_tab);
+  if (mode == INTEGER)
+    {
+      int i;
+      for (i = 0; i < n_sorted_tab; i++)
+        {
+          free (sorted_tab[i]->u.data);
+          free (sorted_tab[i]);
+        }
+      free (sorted_tab);
+    }
 }
 
-static void insert_summary (struct tab_table *, int tab_index, double valid);
+static void insert_summary (struct tab_table *, int tab_index,
+                           const struct dictionary *,
+                           double valid);
 
 /* Output a table summarizing the cases processed. */
 static void
-make_summary_table (void)
+make_summary_table (const struct dictionary *dict)
 {
   struct tab_table *summary;
-  
+
   struct table_entry **pb = sorted_tab, **pe;
   int pc = n_sorted_tab;
   int cur_tab = 0;
@@ -837,17 +880,17 @@ make_summary_table (void)
       }
   }
   tab_offset (summary, 0, 3);
-                 
+
   for (;;)
     {
       double valid;
-      
+
       pe = find_pivot_extent (pb, &pc, cmd.pivot == CRS_PIVOT);
       if (pe == NULL)
        break;
 
       while (cur_tab < (*pb)->table)
-       insert_summary (summary, cur_tab++, 0.);
+       insert_summary (summary, cur_tab++, dict, 0.);
 
       if (mode == GENERAL)
        for (valid = 0.; pb < pe; pb++)
@@ -858,23 +901,23 @@ make_summary_table (void)
          const int n_cols = get_var_range (x->vars[COL_VAR])->count;
          const int n_rows = get_var_range (x->vars[ROW_VAR])->count;
          const int count = n_cols * n_rows;
-           
+
          for (valid = 0.; pb < pe; pb++)
            {
              const double *data = (*pb)->u.data;
              int i;
-               
+
              for (i = 0; i < count; i++)
                valid += *data++;
            }
        }
-      insert_summary (summary, cur_tab++, valid);
+      insert_summary (summary, cur_tab++, dict, valid);
 
       pb = pe;
     }
-  
+
   while (cur_tab < nxtab)
-    insert_summary (summary, cur_tab++, 0.);
+    insert_summary (summary, cur_tab++, dict, 0.);
 
   submit (summary);
 }
@@ -882,15 +925,20 @@ make_summary_table (void)
 /* Inserts a line into T describing the crosstabulation at index
    TAB_INDEX, which has VALID valid observations. */
 static void
-insert_summary (struct tab_table *t, int tab_index, double valid)
+insert_summary (struct tab_table *t, int tab_index,
+               const struct dictionary *dict,
+               double valid)
 {
   struct crosstab *x = xtab[tab_index];
 
+  const struct variable *wv = dict_get_weight (dict);
+  const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : & F_8_0;
+
   tab_hline (t, TAL_1, 0, 6, 0);
-  
+
   /* Crosstabulation name. */
   {
-    char *buf = local_alloc (128 * x->nvar);
+    char *buf = xmalloca (128 * x->nvar);
     char *cp = buf;
     int i;
 
@@ -903,9 +951,9 @@ insert_summary (struct tab_table *t, int tab_index, double valid)
       }
     tab_text (t, 0, 0, TAB_LEFT, buf);
 
-    local_free (buf);
+    freea (buf);
   }
-    
+
   /* Counts and percentages. */
   {
     double n[3];
@@ -918,12 +966,12 @@ insert_summary (struct tab_table *t, int tab_index, double valid)
 
     for (i = 0; i < 3; i++)
       {
-       tab_float (t, i * 2 + 1, 0, TAB_RIGHT, n[i], 8, 0);
+       tab_double (t, i * 2 + 1, 0, TAB_RIGHT, n[i], wfmt);
        tab_text (t, i * 2 + 2, 0, TAB_RIGHT | TAT_PRINTF, "%.1f%%",
                  n[i] / n[2] * 100.);
       }
   }
-  
+
   tab_next_row (t);
 }
 \f
@@ -946,7 +994,7 @@ static int n_cols;
 /* Row values, number of rows. */
 static union value *rows;
 static int n_rows;
-             
+
 /* Number of statistically interesting columns/rows (columns/rows with
    data in them). */
 static int ns_cols, ns_rows;
@@ -967,11 +1015,11 @@ static double W;         /* Grand total. */
 static void display_dimensions (struct tab_table *, int first_difference,
                                struct table_entry *);
 static void display_crosstabulation (void);
-static void display_chisq (void);
-static void display_symmetric (void);
-static void display_risk (void);
+static void display_chisq (const struct dictionary *);
+static void display_symmetric (const struct dictionary *);
+static void display_risk (const struct dictionary *);
 static void display_directional (void);
-static void crosstabs_dim (struct tab_table *, struct outp_driver *);
+static void crosstabs_dim (struct tab_table *, struct outp_driver *, void *);
 static void table_value_missing (struct tab_table *table, int c, int r,
                                 unsigned char opt, const union value *v,
                                 const struct variable *var);
@@ -982,6 +1030,7 @@ static void delete_missing (void);
    hold *MAXROWS entries. */
 static void
 output_pivot_table (struct table_entry **pb, struct table_entry **pe,
+                   const struct dictionary *dict,
                    double **matp, double **row_totp, double **col_totp,
                    int *maxrows, int *maxcols, int *maxcells)
 {
@@ -1007,9 +1056,9 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe,
       /* First header line. */
       tab_joint_text (table, nvar - 1, 0, (nvar - 1) + (n_cols - 1), 0,
                      TAB_CENTER | TAT_TITLE, var_get_name (x->vars[COL_VAR]));
-  
+
       tab_hline (table, TAL_1, nvar - 1, nvar + n_cols - 2, 1);
-            
+
       /* Second header line. */
       {
        int i;
@@ -1030,10 +1079,10 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe,
 
       /* Title. */
       {
-       char *title = local_alloc (x->nvar * 64 + 128);
+       char *title = xmalloca (x->nvar * 64 + 128);
        char *cp = title;
        int i;
-    
+
        if (cmd.pivot == CRS_PIVOT)
          for (i = 0; i < nvar; i++)
            {
@@ -1071,8 +1120,8 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe,
                int value;
                const char *name;
              };
-       
-           static const struct tuple cell_names[] = 
+
+           static const struct tuple cell_names[] =
              {
                {CRS_CL_COUNT, N_("count")},
                {CRS_CL_ROW, N_("row %")},
@@ -1096,14 +1145,14 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe,
        strcpy (cp, "].");
 
        tab_title (table, "%s", title);
-       local_free (title);
+       freea (title);
       }
-      
+
       tab_offset (table, 0, 2);
     }
   else
     table = NULL;
-  
+
   /* Chi-square table initialization. */
   if (cmd.a_statistics[CRS_ST_CHISQ])
     {
@@ -1112,7 +1161,7 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe,
       tab_headers (chisq, 1 + (nvar - 2), 0, 1, 0);
 
       tab_title (chisq, _("Chi-square tests."));
-      
+
       tab_offset (chisq, nvar - 2, 0);
       tab_text (chisq, 0, 0, TAB_LEFT | TAT_TITLE, _("Statistic"));
       tab_text (chisq, 1, 0, TAB_RIGHT | TAT_TITLE, _("Value"));
@@ -1128,7 +1177,7 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe,
     }
   else
     chisq = NULL;
-  
+
   /* Symmetric measures. */
   if (cmd.a_statistics[CRS_ST_PHI] || cmd.a_statistics[CRS_ST_CC]
       || cmd.a_statistics[CRS_ST_BTAU] || cmd.a_statistics[CRS_ST_CTAU]
@@ -1216,7 +1265,7 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe,
          col_tot = *col_totp;
          *maxcols = n_cols;
        }
-      
+
       /* Allocate table space for the matrix. */
       if (table && tab_row (table) + (n_rows + 1) * num_cells > tab_nr (table))
        tab_realloc (table, -1,
@@ -1231,7 +1280,7 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe,
              *matp = xnrealloc (*matp, n_cols * n_rows, sizeof **matp);
              *maxcells = n_cols * n_rows;
            }
-         
+
          mat = *matp;
 
          /* Build the matrix and calculate column totals. */
@@ -1298,7 +1347,7 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe,
        {
          int r, c;
          double *tp = col_tot;
-         
+
          assert (mode == INTEGER);
          mat = (*tb)->u.data;
          ns_cols = n_cols;
@@ -1308,16 +1357,16 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe,
            {
              double cum = 0.;
              double *cp = &mat[c];
-             
+
              for (r = 0; r < n_rows; r++)
                cum += cp[r * n_cols];
              *tp++ = cum;
            }
        }
-      
+
       {
        double *cp;
-       
+
        for (ns_cols = 0, cp = col_tot; cp < &col_tot[n_cols]; cp++)
          ns_cols += *cp != 0.;
       }
@@ -1327,7 +1376,7 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe,
        double *mp = mat;
        double *rp = row_tot;
        int r, c;
-               
+
        for (ns_rows = 0, r = n_rows; r--; )
          {
            double cum = 0.;
@@ -1353,13 +1402,13 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe,
          cum += *tp++;
        W = cum;
       }
-      
+
       /* Find the first variable that differs from the last subtable,
         then display the values of the dimensioning variables for
         each table that needs it. */
       {
        int first_difference = nvar - 1;
-       
+
        if (tb != pb)
          for (; ; first_difference--)
            {
@@ -1370,7 +1419,7 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe,
                break;
            }
        cmp = *tb;
-           
+
        if (table)
          display_dimensions (table, first_difference, *tb);
        if (chisq)
@@ -1388,20 +1437,20 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe,
       if (cmd.miss == CRS_REPORT)
        delete_missing ();
       if (chisq)
-       display_chisq ();
+       display_chisq (dict);
       if (sym)
-       display_symmetric ();
+       display_symmetric (dict);
       if (risk)
-       display_risk ();
+       display_risk (dict);
       if (direct)
        display_directional ();
-               
+
       tb = te;
       free (rows);
     }
 
   submit (table);
-  
+
   if (chisq)
     {
       if (!chisq_fisher)
@@ -1434,7 +1483,7 @@ delete_missing (void)
          ns_rows--;
        }
   }
-  
+
   {
     int c;
 
@@ -1455,10 +1504,10 @@ static void
 submit (struct tab_table *t)
 {
   int i;
-  
+
   if (t == NULL)
     return;
-  
+
   tab_resize (t, -1, 0);
   if (tab_nr (t) == tab_t (t))
     {
@@ -1476,17 +1525,17 @@ submit (struct tab_table *t)
   tab_box (t, -1, -1, -1, TAL_GAP, 0, tab_t (t), tab_l (t) - 1,
           tab_nr (t) - 1);
   tab_vline (t, TAL_2, tab_l (t), 0, tab_nr (t) - 1);
-  tab_dim (t, crosstabs_dim);
+  tab_dim (t, crosstabs_dim, NULL);
   tab_submit (t);
 }
 
 /* Sets the widths of all the columns and heights of all the rows in
    table T for driver D. */
 static void
-crosstabs_dim (struct tab_table *t, struct outp_driver *d)
+crosstabs_dim (struct tab_table *t, struct outp_driver *d, void *aux UNUSED)
 {
   int i;
-  
+
   /* Width of a numerical column. */
   int c = outp_string_width (d, "0.000000", OUTP_PROPORTIONAL);
   if (cmd.miss == CRS_REPORT)
@@ -1502,7 +1551,7 @@ crosstabs_dim (struct tab_table *t, struct outp_driver *d)
       for (i = 0; i <= t->nc; i++)
         w -= t->wrv[i];
       w /= t->l;
-      
+
       if (w < d->prop_em_width * 8)
        w = d->prop_em_width * 8;
 
@@ -1597,7 +1646,7 @@ find_pivot_extent_integer (struct table_entry **tp, int *cnt, int pivot)
        break;
       if (pivot)
        continue;
-      
+
       if (memcmp (&(*tp)->values[2], &fp->values[2],
                   sizeof (union value) * (x->nvar - 2)))
        break;
@@ -1629,15 +1678,15 @@ compare_value (const void *a_, const void *b_, const void *width_)
    malloc()'darray stored in *VALUES, with the number of values
    stored in *VALUE_CNT.
    */
-static void 
+static void
 enum_var_values (struct table_entry **entries, int entry_cnt, int var_idx,
                  union value **values, int *value_cnt)
 {
-  struct variable *v = xtab[(*entries)->table]->vars[var_idx];
+  const struct variable *v = xtab[(*entries)->table]->vars[var_idx];
 
   if (mode == GENERAL)
     {
-      int width = var_get_width (v);
+      int width = MIN (var_get_width (v), MAX_SHORT_STRING);
       int i;
 
       *values = xnmalloc (entry_cnt, sizeof **values);
@@ -1650,7 +1699,7 @@ enum_var_values (struct table_entry **entries, int entry_cnt, int var_idx,
     {
       struct var_range *vr = get_var_range (v);
       int i;
-      
+
       assert (mode == INTEGER);
       *values = xnmalloc (vr->count, sizeof **values);
       for (i = 0; i < vr->count; i++)
@@ -1670,7 +1719,7 @@ table_value_missing (struct tab_table *table, int c, int r, unsigned char opt,
   const struct fmt_spec *print = var_get_print_format (var);
 
   const char *label = var_lookup_value_label (var, v);
-  if (label) 
+  if (label)
     {
       tab_text (table, c, r, TAB_LEFT, label);
       return;
@@ -1715,7 +1764,7 @@ format_cell_entry (struct tab_table *table, int c, int r, double value,
   const struct fmt_spec f = {FMT_F, 10, 1};
   union value v;
   struct substring s;
-  
+
   s.length = 10;
   s.string = tab_alloc (table, 16);
   v.f = value;
@@ -1739,14 +1788,14 @@ display_crosstabulation (void)
 {
   {
     int r;
-       
+
     for (r = 0; r < n_rows; r++)
       table_value_missing (table, nvar - 2, r * num_cells,
                           TAB_RIGHT, &rows[r], x->vars[ROW_VAR]);
   }
   tab_text (table, nvar - 2, n_rows * num_cells,
            TAB_LEFT, _("Total"));
-      
+
   /* Put in the actual cells. */
   {
     double *mp = mat;
@@ -1822,9 +1871,8 @@ display_crosstabulation (void)
     int r, i;
 
     tab_offset (table, -1, tab_row (table) - num_cells * n_rows);
-    for (r = 0; r < n_rows; r++) 
+    for (r = 0; r < n_rows; r++)
       {
-        char suffix = 0;
         bool mark_missing = false;
 
         if (cmd.miss == CRS_REPORT
@@ -1833,6 +1881,7 @@ display_crosstabulation (void)
 
         for (i = 0; i < num_cells; i++)
           {
+            char suffix = 0;
             double v;
 
             switch (cells[i])
@@ -1841,7 +1890,7 @@ display_crosstabulation (void)
                 v = row_tot[r];
                 break;
               case CRS_CL_ROW:
-                v = 100.;
+                v = 100.0;
                 suffix = '%';
                 break;
               case CRS_CL_COLUMN:
@@ -1864,7 +1913,7 @@ display_crosstabulation (void)
 
             format_cell_entry (table, n_cols, 0, v, suffix, mark_missing);
             tab_next_row (table);
-          } 
+          }
       }
   }
 
@@ -1879,22 +1928,21 @@ display_crosstabulation (void)
       {
        double ct = c < n_cols ? col_tot[c] : W;
         bool mark_missing = false;
-        char suffix = 0;
         int i;
-           
-        if (cmd.miss == CRS_REPORT && c < n_cols 
+
+        if (cmd.miss == CRS_REPORT && c < n_cols
             && var_is_num_missing (x->vars[COL_VAR], cols[c].f, MV_USER))
           mark_missing = true;
 
         for (i = 0; i < num_cells; i++)
          {
+            char suffix = 0;
            double v;
 
            switch (cells[i])
              {
              case CRS_CL_COUNT:
                v = ct;
-                suffix = '%';
                break;
              case CRS_CL_ROW:
                v = ct / W * 100.;
@@ -1917,14 +1965,14 @@ display_crosstabulation (void)
                 NOT_REACHED ();
              }
 
-            format_cell_entry (table, c, i, v, suffix, mark_missing);
+           format_cell_entry (table, c, i, v, suffix, mark_missing);
          }
         last_row = i;
       }
 
     tab_offset (table, -1, tab_row (table) + last_row);
   }
-  
+
   tab_offset (table, 0, -1);
 }
 
@@ -1933,9 +1981,12 @@ static void calc_chisq (double[N_CHISQ], int[N_CHISQ], double *, double *);
 
 /* Display chi-square statistics. */
 static void
-display_chisq (void)
+display_chisq (const struct dictionary *dict)
 {
-  static const char *chisq_stats[N_CHISQ] = 
+  const struct variable *wv = dict_get_weight (dict);
+  const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : & F_8_0;
+
+  static const char *chisq_stats[N_CHISQ] =
     {
       N_("Pearson Chi-Square"),
       N_("Likelihood Ratio"),
@@ -1949,39 +2000,39 @@ display_chisq (void)
   int s = 0;
 
   int i;
-             
+
   calc_chisq (chisq_v, df, &fisher1, &fisher2);
 
   tab_offset (chisq, nvar - 2, -1);
-  
+
   for (i = 0; i < N_CHISQ; i++)
     {
       if ((i != 2 && chisq_v[i] == SYSMIS)
          || (i == 2 && fisher1 == SYSMIS))
        continue;
       s = 1;
-      
+
       tab_text (chisq, 0, 0, TAB_LEFT, gettext (chisq_stats[i]));
       if (i != 2)
        {
-         tab_float (chisq, 1, 0, TAB_RIGHT, chisq_v[i], 8, 3);
-         tab_float (chisq, 2, 0, TAB_RIGHT, df[i], 8, 0);
-         tab_float (chisq, 3, 0, TAB_RIGHT,
-                    gsl_cdf_chisq_Q (chisq_v[i], df[i]), 8, 3);
+         tab_double (chisq, 1, 0, TAB_RIGHT, chisq_v[i], NULL);
+         tab_double (chisq, 2, 0, TAB_RIGHT, df[i], wfmt);
+         tab_double (chisq, 3, 0, TAB_RIGHT,
+                    gsl_cdf_chisq_Q (chisq_v[i], df[i]), NULL);
        }
       else
        {
          chisq_fisher = 1;
-         tab_float (chisq, 4, 0, TAB_RIGHT, fisher2, 8, 3);
-         tab_float (chisq, 5, 0, TAB_RIGHT, fisher1, 8, 3);
+         tab_double (chisq, 4, 0, TAB_RIGHT, fisher2, NULL);
+         tab_double (chisq, 5, 0, TAB_RIGHT, fisher1, NULL);
        }
       tab_next_row (chisq);
     }
 
   tab_text (chisq, 0, 0, TAB_LEFT, _("N of Valid Cases"));
-  tab_float (chisq, 1, 0, TAB_RIGHT, W, 8, 0);
+  tab_double (chisq, 1, 0, TAB_RIGHT, W, wfmt);
   tab_next_row (chisq);
-    
+
   tab_offset (chisq, 0, -1);
 }
 
@@ -1990,9 +2041,12 @@ static int calc_symmetric (double[N_SYMMETRIC], double[N_SYMMETRIC],
 
 /* Display symmetric measures. */
 static void
-display_symmetric (void)
+display_symmetric (const struct dictionary *dict)
 {
-  static const char *categories[] = 
+  const struct variable *wv = dict_get_weight (dict);
+  const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : & F_8_0;
+
+  static const char *categories[] =
     {
       N_("Nominal by Nominal"),
       N_("Ordinal by Ordinal"),
@@ -2026,7 +2080,7 @@ display_symmetric (void)
     return;
 
   tab_offset (sym, nvar - 2, -1);
-  
+
   for (i = 0; i < N_SYMMETRIC; i++)
     {
       if (sym_v[i] == SYSMIS)
@@ -2037,21 +2091,21 @@ display_symmetric (void)
          last_cat = stats_categories[i];
          tab_text (sym, 0, 0, TAB_LEFT, gettext (categories[last_cat]));
        }
-      
+
       tab_text (sym, 1, 0, TAB_LEFT, gettext (stats[i]));
-      tab_float (sym, 2, 0, TAB_RIGHT, sym_v[i], 8, 3);
+      tab_double (sym, 2, 0, TAB_RIGHT, sym_v[i], NULL);
       if (sym_ase[i] != SYSMIS)
-       tab_float (sym, 3, 0, TAB_RIGHT, sym_ase[i], 8, 3);
+       tab_double (sym, 3, 0, TAB_RIGHT, sym_ase[i], NULL);
       if (sym_t[i] != SYSMIS)
-       tab_float (sym, 4, 0, TAB_RIGHT, sym_t[i], 8, 3);
-      /*tab_float (sym, 5, 0, TAB_RIGHT, normal_sig (sym_v[i]), 8, 3);*/
+       tab_double (sym, 4, 0, TAB_RIGHT, sym_t[i], NULL);
+      /*tab_double (sym, 5, 0, TAB_RIGHT, normal_sig (sym_v[i]), NULL);*/
       tab_next_row (sym);
     }
 
   tab_text (sym, 0, 0, TAB_LEFT, _("N of Valid Cases"));
-  tab_float (sym, 2, 0, TAB_RIGHT, W, 8, 0);
+  tab_double (sym, 2, 0, TAB_RIGHT, W, wfmt);
   tab_next_row (sym);
-    
+
   tab_offset (sym, 0, -1);
 }
 
@@ -2059,18 +2113,21 @@ static int calc_risk (double[], double[], double[], union value *);
 
 /* Display risk estimate. */
 static void
-display_risk (void)
+display_risk (const struct dictionary *dict)
 {
+  const struct variable *wv = dict_get_weight (dict);
+  const struct fmt_spec *wfmt = wv ? var_get_print_format (wv) : & F_8_0;
+
   char buf[256];
   double risk_v[3], lower[3], upper[3];
   union value c[2];
   int i;
-  
+
   if (!calc_risk (risk_v, upper, lower, c))
     return;
-  
+
   tab_offset (risk, nvar - 2, -1);
-  
+
   for (i = 0; i < 3; i++)
     {
       if (risk_v[i] == SYSMIS)
@@ -2099,18 +2156,18 @@ display_risk (void)
                     var_get_width (x->vars[ROW_VAR]), rows[i - 1].s);
          break;
        }
-                  
+
       tab_text (risk, 0, 0, TAB_LEFT, buf);
-      tab_float (risk, 1, 0, TAB_RIGHT, risk_v[i], 8, 3);
-      tab_float (risk, 2, 0, TAB_RIGHT, lower[i], 8, 3);
-      tab_float (risk, 3, 0, TAB_RIGHT, upper[i], 8, 3);
+      tab_double (risk, 1, 0, TAB_RIGHT, risk_v[i], NULL);
+      tab_double (risk, 2, 0, TAB_RIGHT, lower[i],  NULL);
+      tab_double (risk, 3, 0, TAB_RIGHT, upper[i],  NULL);
       tab_next_row (risk);
     }
 
   tab_text (risk, 0, 0, TAB_LEFT, _("N of Valid Cases"));
-  tab_float (risk, 1, 0, TAB_RIGHT, W, 8, 0);
+  tab_double (risk, 1, 0, TAB_RIGHT, W, wfmt);
   tab_next_row (risk);
-    
+
   tab_offset (risk, 0, -1);
 }
 
@@ -2121,7 +2178,7 @@ static int calc_directional (double[N_DIRECTIONAL], double[N_DIRECTIONAL],
 static void
 display_directional (void)
 {
-  static const char *categories[] = 
+  static const char *categories[] =
     {
       N_("Nominal by Nominal"),
       N_("Ordinal by Ordinal"),
@@ -2137,7 +2194,7 @@ display_directional (void)
       N_("Eta"),
     };
 
-  static const char *types[] = 
+  static const char *types[] =
     {
       N_("Symmetric"),
       N_("%s Dependent"),
@@ -2148,18 +2205,18 @@ display_directional (void)
     {
       0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2,
     };
-  
-  static const int stats_stats[N_DIRECTIONAL] = 
+
+  static const int stats_stats[N_DIRECTIONAL] =
     {
       0, 0, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4,
     };
 
-  static const int stats_types[N_DIRECTIONAL] = 
+  static const int stats_types[N_DIRECTIONAL] =
     {
       0, 1, 2, 1, 2, 0, 1, 2, 0, 1, 2, 1, 2,
     };
 
-  static const int *stats_lookup[] = 
+  static const int *stats_lookup[] =
     {
       stats_categories,
       stats_stats,
@@ -2177,23 +2234,23 @@ display_directional (void)
     {
       -1, -1, -1,
     };
-    
+
   double direct_v[N_DIRECTIONAL];
   double direct_ase[N_DIRECTIONAL];
   double direct_t[N_DIRECTIONAL];
-  
+
   int i;
 
   if (!calc_directional (direct_v, direct_ase, direct_t))
     return;
 
   tab_offset (direct, nvar - 2, -1);
-  
+
   for (i = 0; i < N_DIRECTIONAL; i++)
     {
       if (direct_v[i] == SYSMIS)
        continue;
-      
+
       {
        int j;
 
@@ -2202,7 +2259,7 @@ display_directional (void)
            {
              if (j < 2)
                tab_hline (direct, TAL_1, j, 6, 0);
-             
+
              for (; j < 3; j++)
                {
                  const char *string;
@@ -2214,19 +2271,19 @@ display_directional (void)
                    string = var_get_name (x->vars[0]);
                  else
                    string = var_get_name (x->vars[1]);
-                 
+
                  tab_text (direct, j, 0, TAB_LEFT | TAT_PRINTF,
                            gettext (stats_names[j][k]), string);
                }
            }
       }
-      
-      tab_float (direct, 3, 0, TAB_RIGHT, direct_v[i], 8, 3);
+
+      tab_double (direct, 3, 0, TAB_RIGHT, direct_v[i], NULL);
       if (direct_ase[i] != SYSMIS)
-       tab_float (direct, 4, 0, TAB_RIGHT, direct_ase[i], 8, 3);
+       tab_double (direct, 4, 0, TAB_RIGHT, direct_ase[i], NULL);
       if (direct_t[i] != SYSMIS)
-       tab_float (direct, 5, 0, TAB_RIGHT, direct_t[i], 8, 3);
-      /*tab_float (direct, 6, 0, TAB_RIGHT, normal_sig (direct_v[i]), 8, 3);*/
+       tab_double (direct, 5, 0, TAB_RIGHT, direct_t[i], NULL);
+      /*tab_double (direct, 6, 0, TAB_RIGHT, normal_sig (direct_v[i]), NULL);*/
       tab_next_row (direct);
     }
 
@@ -2242,7 +2299,7 @@ gamma_int (double x)
 {
   double r = 1;
   int i;
-  
+
   for (i = 2; i < x; i++)
     r *= i;
   return r;
@@ -2275,7 +2332,7 @@ static void
 calc_fisher (int a, int b, int c, int d, double *fisher1, double *fisher2)
 {
   int x;
-  
+
   if (MIN (c, d) < MIN (a, b))
     swap (&a, &c), swap (&b, &d);
   if (MIN (b, d) < MIN (a, c))
@@ -2324,7 +2381,7 @@ calc_chisq (double chisq[N_CHISQ], int df[N_CHISQ],
        const double expected = row_tot[r] * col_tot[c] / W;
        const double freq = mat[n_cols * r + c];
        const double residual = freq - expected;
-    
+
         chisq[0] += residual * residual / expected;
        if (freq)
          chisq[1] += freq * log (expected / freq);
@@ -2342,7 +2399,7 @@ calc_chisq (double chisq[N_CHISQ], int df[N_CHISQ],
   if (ns_cols == 2 && ns_rows == 2)
     {
       double f11, f12, f21, f22;
-      
+
       {
        int nz_cols[2];
        int i, j;
@@ -2387,7 +2444,7 @@ calc_chisq (double chisq[N_CHISQ], int df[N_CHISQ],
     {
       double r, ase_0, ase_1;
       calc_r ((double *) rows, (double *) cols, &r, &ase_0, &ase_1);
-    
+
       chisq[4] = (W - 1.) * r * r;
       df[4] = 1;
     }
@@ -2419,7 +2476,7 @@ calc_r (double *X, double *Y, double *r, double *ase_0, double *ase_1)
   for (sum_Xr = sum_X2r = 0., i = 0; i < n_rows; i++)
     {
       sum_Xr += X[i] * row_tot[i];
-      sum_X2r += X[i] * X[i] * row_tot[i];
+      sum_X2r += pow2 (X[i]) * row_tot[i];
     }
   Xbar = sum_Xr / W;
 
@@ -2431,15 +2488,15 @@ calc_r (double *X, double *Y, double *r, double *ase_0, double *ase_1)
   Ybar = sum_Yc / W;
 
   S = sum_XYf - sum_Xr * sum_Yc / W;
-  SX = sum_X2r - sum_Xr * sum_Xr / W;
-  SY = sum_Y2c - sum_Yc * sum_Yc / W;
+  SX = sum_X2r - pow2 (sum_Xr) / W;
+  SY = sum_Y2c - pow2 (sum_Yc) / W;
   T = sqrt (SX * SY);
   *r = S / T;
-  *ase_0 = sqrt ((sum_X2Y2f - (sum_XYf * sum_XYf) / W) / (sum_X2r * sum_Y2c));
-  
+  *ase_0 = sqrt ((sum_X2Y2f - pow2 (sum_XYf) / W) / (sum_X2r * sum_Y2c));
+
   {
     double s, c, y, t;
-    
+
     for (s = c = 0., i = 0; i < n_rows; i++)
       for (j = 0; j < n_cols; j++)
        {
@@ -2471,14 +2528,14 @@ calc_symmetric (double v[N_SYMMETRIC], double ase[N_SYMMETRIC],
                double t[N_SYMMETRIC])
 {
   int q = MIN (ns_rows, ns_cols);
-  
+
   if (q <= 1)
     return 0;
-  
+
   {
     int i;
 
-    if (v) 
+    if (v)
       for (i = 0; i < N_SYMMETRIC; i++)
        v[i] = ase[i] = t[i] = SYSMIS;
   }
@@ -2490,14 +2547,14 @@ calc_symmetric (double v[N_SYMMETRIC], double ase[N_SYMMETRIC],
 
       {
        int r, c;
-    
+
        for (r = 0; r < n_rows; r++)
          for (c = 0; c < n_cols; c++)
            {
              const double expected = row_tot[r] * col_tot[c] / W;
              const double freq = mat[n_cols * r + c];
              const double residual = freq - expected;
-    
+
               Xp += residual * residual / expected;
            }
       }
@@ -2510,7 +2567,7 @@ calc_symmetric (double v[N_SYMMETRIC], double ase[N_SYMMETRIC],
       if (cmd.a_statistics[CRS_ST_CC])
        v[2] = sqrt (Xp / (Xp + W));
     }
-  
+
   if (cmd.a_statistics[CRS_ST_BTAU] || cmd.a_statistics[CRS_ST_CTAU]
       || cmd.a_statistics[CRS_ST_GAMMA] || cmd.a_statistics[CRS_ST_D])
     {
@@ -2519,17 +2576,17 @@ calc_symmetric (double v[N_SYMMETRIC], double ase[N_SYMMETRIC],
       double P, Q;
       double btau_cum, ctau_cum, gamma_cum, d_yx_cum, d_xy_cum;
       double btau_var;
-      
+
       {
        int r, c;
-       
+
        Dr = Dc = W * W;
        for (r = 0; r < n_rows; r++)
-         Dr -= row_tot[r] * row_tot[r];
+         Dr -= pow2 (row_tot[r]);
        for (c = 0; c < n_cols; c++)
-         Dc -= col_tot[c] * col_tot[c];
+         Dc -= pow2 (col_tot[c]);
       }
-      
+
       {
        int r, c;
 
@@ -2537,12 +2594,12 @@ calc_symmetric (double v[N_SYMMETRIC], double ase[N_SYMMETRIC],
        for (c = 0; c < n_cols; c++)
          {
            double ct = 0.;
-           
+
            for (r = 0; r < n_rows; r++)
              cum[c + r * n_cols] = ct += mat[c + r * n_cols];
          }
       }
-      
+
       /* P and Q. */
       {
        int i, j;
@@ -2565,14 +2622,14 @@ calc_symmetric (double v[N_SYMMETRIC], double ase[N_SYMMETRIC],
                double fij = mat[j + i * n_cols];
                P += fij * Cij;
                Q += fij * Dij;
-               
+
                if (++j == n_cols)
                  break;
                assert (j < n_cols);
 
                Cij -= col_tot[j] - cum[j + i * n_cols];
                Dij += col_tot[j - 1] - cum[j - 1 + i * n_cols];
-               
+
                if (i > 0)
                  {
                    Cij += cum[j - 1 + (i - 1) * n_cols];
@@ -2618,7 +2675,7 @@ calc_symmetric (double v[N_SYMMETRIC], double ase[N_SYMMETRIC],
                                                   + col_tot[j] * Dr));
                    btau_cum += fij * temp * temp;
                  }
-               
+
                {
                  const double temp = Cij - Dij;
                  ctau_cum += fij * temp * temp;
@@ -2637,14 +2694,14 @@ calc_symmetric (double v[N_SYMMETRIC], double ase[N_SYMMETRIC],
                    d_xy_cum += fij * pow2 (Dc * (Dij - Cij)
                                             - (Q - P) * (W - col_tot[j]));
                  }
-               
+
                if (++j == n_cols)
                  break;
                assert (j < n_cols);
 
                Cij -= col_tot[j] - cum[j + i * n_cols];
                Dij += col_tot[j - 1] - cum[j - 1 + i * n_cols];
-               
+
                if (i > 0)
                  {
                    Cij += cum[j - 1 + (i - 1) * n_cols];
@@ -2700,13 +2757,13 @@ calc_symmetric (double v[N_SYMMETRIC], double ase[N_SYMMETRIC],
   /* Spearman correlation, Pearson's r. */
   if (cmd.a_statistics[CRS_ST_CORR])
     {
-      double *R = local_alloc (sizeof *R * n_rows);
-      double *C = local_alloc (sizeof *C * n_cols);
-      
+      double *R = xmalloca (sizeof *R * n_rows);
+      double *C = xmalloca (sizeof *C * n_cols);
+
       {
        double y, t, c = 0., s = 0.;
        int i = 0;
-       
+
        for (;;)
          {
            R[i] = s + (row_tot[i] + 1.) / 2.;
@@ -2719,11 +2776,11 @@ calc_symmetric (double v[N_SYMMETRIC], double ase[N_SYMMETRIC],
            assert (i < n_rows);
          }
       }
-      
+
       {
        double y, t, c = 0., s = 0.;
        int j = 0;
-       
+
        for (;;)
          {
            C[j] = s + (col_tot[j] + 1.) / 2;
@@ -2736,12 +2793,12 @@ calc_symmetric (double v[N_SYMMETRIC], double ase[N_SYMMETRIC],
            assert (j < n_cols);
          }
       }
-      
+
       calc_r (R, C, &v[6], &t[6], &ase[6]);
       t[6] = v[6] / t[6];
 
-      local_free (R);
-      local_free (C);
+      freea (R);
+      freea (C);
 
       calc_r ((double *) rows, (double *) cols, &v[7], &t[7], &ase[7]);
       t[7] = v[7] / t[7];
@@ -2752,18 +2809,18 @@ calc_symmetric (double v[N_SYMMETRIC], double ase[N_SYMMETRIC],
     {
       double sum_fii, sum_rici, sum_fiiri_ci, sum_fijri_ci2, sum_riciri_ci;
       int i, j;
-      
+
       for (sum_fii = sum_rici = sum_fiiri_ci = sum_riciri_ci = 0., i = j = 0;
           i < ns_rows; i++, j++)
        {
          double prod, sum;
-         
+
          while (col_tot[j] == 0.)
            j++;
-         
+
          prod = row_tot[i] * col_tot[j];
          sum = row_tot[i] + col_tot[j];
-         
+
          sum_fii += mat[j + i * n_cols];
          sum_rici += prod;
          sum_fiiri_ci += mat[j + i * n_cols] * sum;
@@ -2775,7 +2832,7 @@ calc_symmetric (double v[N_SYMMETRIC], double ase[N_SYMMETRIC],
            double sum = row_tot[i] + col_tot[j];
            sum_fijri_ci2 += mat[j + i * n_cols] * sum * sum;
          }
-      
+
       v[8] = (W * sum_fii - sum_rici) / (W * W - sum_rici);
 
       ase[8] = sqrt ((W * W * sum_rici
@@ -2810,14 +2867,14 @@ calc_risk (double *value, double *upper, double *lower, union value *c)
 
   {
     int i;
-      
+
     for (i = 0; i < 3; i++)
       value[i] = upper[i] = lower[i] = SYSMIS;
   }
-    
+
   if (ns_rows != 2 || ns_cols != 2)
     return 0;
-  
+
   {
     int nz_cols[2];
     int i, j;
@@ -2851,7 +2908,7 @@ calc_risk (double *value, double *upper, double *lower, union value *c)
            + (f22 / (f21 * (f21 + f22))));
   lower[1] = value[1] * exp (-1.960 * v);
   upper[1] = value[1] * exp (1.960 * v);
-    
+
   value[2] = (f12 * (f21 + f22)) / (f22 * (f11 + f12));
   v = sqrt ((f11 / (f12 * (f11 + f12)))
            + (f21 / (f22 * (f21 + f22))));
@@ -2897,7 +2954,7 @@ calc_directional (double v[N_DIRECTIONAL], double ase[N_DIRECTIONAL],
                max = mat[j + i * n_cols];
                index = j;
              }
-       
+
          sum_fim += fim[i] = max;
          fim_index[i] = index;
        }
@@ -2914,7 +2971,7 @@ calc_directional (double v[N_DIRECTIONAL], double ase[N_DIRECTIONAL],
                max = mat[j + i * n_cols];
                index = i;
              }
-       
+
          sum_fmj += fmj[j] = max;
          fmj_index[j] = index;
        }
@@ -2956,14 +3013,14 @@ calc_directional (double v[N_DIRECTIONAL], double ase[N_DIRECTIONAL],
                               - deltaj
                               + v[0] * deltaj));
            }
-      
+
        ase[2] = sqrt (accum - W * v[0]) / (W - cm);
       }
 
       /* ASE0 for Y given X. */
       {
        double accum;
-      
+
        for (accum = 0., i = 0; i < n_rows; i++)
          if (cm_index != fim_index[i])
            accum += (mat[i * n_cols + fim_index[i]]
@@ -2984,14 +3041,14 @@ calc_directional (double v[N_DIRECTIONAL], double ase[N_DIRECTIONAL],
                               - deltaj
                               + v[0] * deltaj));
            }
-      
+
        ase[1] = sqrt (accum - W * v[0]) / (W - rm);
       }
 
       /* ASE0 for X given Y. */
       {
        double accum;
-      
+
        for (accum = 0., j = 0; j < n_cols; j++)
          if (rm_index != fmj_index[j])
            accum += (mat[j + n_cols * fmj_index[j]]
@@ -3022,7 +3079,7 @@ calc_directional (double v[N_DIRECTIONAL], double ase[N_DIRECTIONAL],
       free (fim_index);
       free (fmj);
       free (fmj_index);
-      
+
       {
        double sum_fij2_ri, sum_fij2_ci;
        double sum_ri2, sum_cj2;
@@ -3036,10 +3093,10 @@ calc_directional (double v[N_DIRECTIONAL], double ase[N_DIRECTIONAL],
            }
 
        for (sum_ri2 = 0., i = 0; i < n_rows; i++)
-         sum_ri2 += row_tot[i] * row_tot[i];
+         sum_ri2 += pow2 (row_tot[i]);
 
        for (sum_cj2 = 0., j = 0; j < n_cols; j++)
-         sum_cj2 += col_tot[j] * col_tot[j];
+         sum_cj2 += pow2 (col_tot[j]);
 
        v[3] = (W * sum_fij2_ci - sum_ri2) / (W * W - sum_ri2);
        v[4] = (W * sum_fij2_ri - sum_cj2) / (W * W - sum_cj2);
@@ -3055,7 +3112,7 @@ calc_directional (double v[N_DIRECTIONAL], double ase[N_DIRECTIONAL],
       for (UX = 0., i = 0; i < n_rows; i++)
        if (row_tot[i] > 0.)
          UX -= row_tot[i] / W * log (row_tot[i] / W);
-      
+
       for (UY = 0., j = 0; j < n_cols; j++)
        if (col_tot[j] > 0.)
          UY -= col_tot[j] / W * log (col_tot[j] / W);
@@ -3067,7 +3124,7 @@ calc_directional (double v[N_DIRECTIONAL], double ase[N_DIRECTIONAL],
 
            if (entry <= 0.)
              continue;
-           
+
            P += entry * pow2 (log (col_tot[j] * row_tot[i] / (W * entry)));
            UXY -= entry / W * log (entry / W);
          }
@@ -3079,7 +3136,7 @@ calc_directional (double v[N_DIRECTIONAL], double ase[N_DIRECTIONAL],
 
            if (entry <= 0.)
              continue;
-           
+
            ase1_yx += entry * pow2 (UY * log (entry / row_tot[i])
                                    + (UX - UXY) * log (col_tot[j] / W));
            ase1_xy += entry * pow2 (UX * log (entry / col_tot[j])
@@ -3088,16 +3145,16 @@ calc_directional (double v[N_DIRECTIONAL], double ase[N_DIRECTIONAL],
                                      * log (row_tot[i] * col_tot[j] / (W * W)))
                                     - (UX + UY) * log (entry / W));
          }
-      
+
       v[5] = 2. * ((UX + UY - UXY) / (UX + UY));
       ase[5] = (2. / (W * pow2 (UX + UY))) * sqrt (ase1_sym);
       t[5] = v[5] / ((2. / (W * (UX + UY)))
                     * sqrt (P - pow2 (UX + UY - UXY) / W));
-                   
+
       v[6] = (UX + UY - UXY) / UX;
       ase[6] = sqrt (ase1_xy) / (W * UX * UX);
       t[6] = v[6] / (sqrt (P - W * pow2 (UX + UY - UXY)) / (W * UX));
-      
+
       v[7] = (UX + UY - UXY) / UY;
       ase[7] = sqrt (ase1_yx) / (W * UY * UY);
       t[7] = v[7] / (sqrt (P - W * pow2 (UX + UY - UXY)) / (W * UY));
@@ -3107,7 +3164,7 @@ calc_directional (double v[N_DIRECTIONAL], double ase[N_DIRECTIONAL],
   if (cmd.a_statistics[CRS_ST_D])
     {
       int i;
-      
+
       if (!sym)
        calc_symmetric (NULL, NULL, NULL);
       for (i = 0; i < 3; i++)
@@ -3125,21 +3182,21 @@ calc_directional (double v[N_DIRECTIONAL], double ase[N_DIRECTIONAL],
        double sum_Xr, sum_X2r;
        double SX, SXW;
        int i, j;
-      
+
        for (sum_Xr = sum_X2r = 0., i = 0; i < n_rows; i++)
          {
            sum_Xr += rows[i].f * row_tot[i];
-           sum_X2r += rows[i].f * rows[i].f * row_tot[i];
+           sum_X2r += pow2 (rows[i].f) * row_tot[i];
          }
-       SX = sum_X2r - sum_Xr * sum_Xr / W;
-      
+       SX = sum_X2r - pow2 (sum_Xr) / W;
+
        for (SXW = 0., j = 0; j < n_cols; j++)
          {
            double cum;
 
            for (cum = 0., i = 0; i < n_rows; i++)
              {
-               SXW += rows[i].f * rows[i].f * mat[j + i * n_cols];
+               SXW += pow2 (rows[i].f) * mat[j + i * n_cols];
                cum += rows[i].f * mat[j + i * n_cols];
              }
 
@@ -3156,7 +3213,7 @@ calc_directional (double v[N_DIRECTIONAL], double ase[N_DIRECTIONAL],
        for (sum_Yc = sum_Y2c = 0., i = 0; i < n_cols; i++)
          {
            sum_Yc += cols[i].f * col_tot[i];
-           sum_Y2c += cols[i].f * cols[i].f * col_tot[i];
+           sum_Y2c += pow2 (cols[i].f) * col_tot[i];
          }
        SY = sum_Y2c - sum_Yc * sum_Yc / W;
 
@@ -3166,10 +3223,10 @@ calc_directional (double v[N_DIRECTIONAL], double ase[N_DIRECTIONAL],
 
            for (cum = 0., j = 0; j < n_cols; j++)
              {
-               SYW += cols[j].f * cols[j].f * mat[j + i * n_cols];
+               SYW += pow2 (cols[j].f) * mat[j + i * n_cols];
                cum += cols[j].f * mat[j + i * n_cols];
              }
-         
+
            SYW -= cum * cum / row_tot[i];
          }
        v[12] = sqrt (1. - SYW / SY);
@@ -3187,7 +3244,7 @@ format_short (char *s, const struct fmt_spec *fp, const union value *v)
   struct fmt_spec fmt_subst;
 
   /* Limit to short string width. */
-  if (fmt_is_string (fp->type)) 
+  if (fmt_is_string (fp->type))
     {
       fmt_subst = *fp;
 
@@ -3202,12 +3259,12 @@ format_short (char *s, const struct fmt_spec *fp, const union value *v)
 
   /* Format. */
   data_out (v, fp, s);
-    
+
   /* Null terminate. */
   s[fp->w] = '\0';
 }
 
-/* 
+/*
    Local Variables:
    mode: c
    End: