Adopt use of gnulib for portability.
[pspp-builds.git] / src / crosstabs.q
index 1f66f066b3457a90cbbd0fd0cb97cee2a1c38184..09873e85e1d71abeab56778b360ea43c1de146ef 100644 (file)
@@ -14,8 +14,8 @@
 
    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., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA. */
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA. */
 
 /* FIXME:
 
@@ -37,6 +37,8 @@
 #include <gsl/gsl_cdf.h>
 #include "algorithm.h"
 #include "alloc.h"
+#include "case.h"
+#include "dictionary.h"
 #include "hash.h"
 #include "pool.h"
 #include "command.h"
 #include "magic.h"
 #include "misc.h"
 #include "output.h"
+#include "str.h"
 #include "tab.h"
 #include "value-labels.h"
 #include "var.h"
 #include "vfm.h"
 
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+#define N_(msgid) msgid
+
+/* (headers) */
+
 #include "debug-print.h"
 
 /* (specification)
    crosstabs (crs_):
-     *tables=custom;
+     *^tables=custom;
      +variables=custom;
      +missing=miss:!table/include/report;
      +write[wr_]=none,cells,all;
@@ -104,6 +113,22 @@ struct crosstab
                                   larger indices first. */
   };
 
+/* Integer mode variable info. */
+struct var_range
+  {
+    int min;                   /* Minimum value. */
+    int max;                   /* Maximum value + 1. */
+    int count;                 /* max - min. */
+  };
+
+static inline struct var_range *
+get_var_range (struct variable *v) 
+{
+  assert (v != NULL);
+  assert (v->aux != NULL);
+  return v->aux;
+}
+
 /* Indexes into crosstab.v. */
 enum
   {
@@ -156,11 +181,6 @@ static void submit (struct tab_table *);
 static void format_short (char *s, const struct fmt_spec *fp,
                          const union value *v);
 
-#if DEBUGGING
-static void debug_print (void);
-static void print_table_entries (struct table_entry **tab);
-#endif
-
 /* Parse and execute CROSSTABS, then clean up. */
 int
 cmd_crosstabs (void)
@@ -190,11 +210,6 @@ internal_cmd_crosstabs (void)
   if (!parse_crosstabs (&cmd))
     return CMD_FAILURE;
 
-#if DEBUGGING
-  /* Needs variables. */
-  debug_print ();
-#endif
-
   mode = variables ? INTEGER : GENERAL;
 
   /* CELLS. */
@@ -327,7 +342,7 @@ crs_custom_tables (struct cmd_crosstabs *cmd UNUSED)
     }
   
   {
-    int *by_iter = xcalloc (sizeof *by_iter * n_by);
+    int *by_iter = xcalloc (n_by, sizeof *by_iter);
     int i;
 
     xtab = xrealloc (xtab, sizeof *xtab * (nxtab + nx));
@@ -435,11 +450,13 @@ crs_custom_variables (struct cmd_crosstabs *cmd UNUSED)
        }
       lex_get ();
       
-      for (i = orig_nv; i < variables_cnt; i++)
-       {
-         variables[i]->p.crs.min = min;
-         variables[i]->p.crs.max = max + 1.;
-         variables[i]->p.crs.count = max - min + 1;
+      for (i = orig_nv; i < variables_cnt; i++) 
+        {
+          struct var_range *vr = xmalloc (sizeof *vr);
+          vr->min = min;
+         vr->max = max + 1.;
+         vr->count = max - min + 1;
+          var_attach_aux (variables[i], vr, var_dtor_free);
        }
       
       if (token == '/')
@@ -453,58 +470,6 @@ crs_custom_variables (struct cmd_crosstabs *cmd UNUSED)
   variables = NULL;
   return 0;
 }
-
-#if DEBUGGING
-static void
-debug_print (void)
-{
-  printf ("CROSSTABS\n");
-
-  if (variables != NULL)
-    {
-      int i;
-
-      printf ("\t/VARIABLES=");
-      for (i = 0; i < variables_cnt; i++)
-       {
-         struct variable *v = variables[i];
-
-         printf ("%s ", v->name);
-         if (i < variables_cnt - 1)
-           {
-             struct variable *nv = variables[i + 1];
-             
-             if (v->p.crs.min == nv->p.crs.min
-                 && v->p.crs.max == nv->p.crs.max)
-               continue;
-           }
-         printf ("(%d,%d) ", v->p.crs.min, v->p.crs.max - 1);
-       }
-      printf ("\n");
-    }
-  
-  {
-    int i;
-
-    printf ("\t/TABLES=");
-    for (i = 0; i < nxtab; i++)
-      {
-       struct crosstab *x = xtab[i];
-       int j;
-
-       if (i)
-         printf("\t\t");
-       for (j = 0; j < x->nvar; j++)
-         {
-           if (j)
-             printf (" BY ");
-           printf ("%s", x->v[j]->name);
-         }
-       printf ("\n");
-      }
-  }
-}
-#endif /* DEBUGGING */
 \f
 /* Data file processing. */
 
@@ -536,14 +501,14 @@ precalc (void *aux UNUSED)
 
          x->ofs = n_sorted_tab;
 
-         for (j = 2; j < x->nvar; j++)
-           count *= x->vars[j - 2]->p.crs.count;
-
+         for (j = 2; j < x->nvar; j++) 
+            count *= get_var_range (x->vars[j - 2])->count;
+          
          sorted_tab = xrealloc (sorted_tab,
                                 sizeof *sorted_tab * (n_sorted_tab + count));
          v = local_alloc (sizeof *v * x->nvar);
-         for (j = 2; j < x->nvar; j++)
-           v[j] = x->vars[j]->p.crs.min;
+         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;
@@ -554,8 +519,9 @@ precalc (void *aux UNUSED)
              te->table = i;
              
              {
-               const int mat_size = (x->vars[0]->p.crs.count
-                                     * x->vars[1]->p.crs.count);
+                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 = xmalloc (sizeof *te->u.data * mat_size);
@@ -565,11 +531,14 @@ precalc (void *aux UNUSED)
              
              for (k = 2; k < x->nvar; k++)
                te->values[k].f = v[k];
-             for (k = 2; k < x->nvar; k++)
-               if (++v[k] >= x->vars[k]->p.crs.max)
-                 v[k] = x->vars[k]->p.crs.min;
-               else
-                 break;
+             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; 
+                }
            }
          local_free (v);
        }
@@ -584,8 +553,10 @@ precalc (void *aux UNUSED)
 static int
 calc_general (struct ccase *c, void *aux UNUSED)
 {
+  int bad_warn = 1;
+
   /* Case weight. */
-  double weight = dict_get_case_weight (default_dict, c);
+  double weight = dict_get_case_weight (default_dict, c, &bad_warn);
 
   /* Flattened current table index. */
   int t;
@@ -606,9 +577,9 @@ calc_general (struct ccase *c, void *aux UNUSED)
        for (j = 0; j < x->nvar; j++)
          {
            if ((cmd.miss == CRS_TABLE
-                && is_missing (&c->data[x->vars[j]->fv], x->vars[j]))
+                && is_missing (case_data (c, x->vars[j]->fv), x->vars[j]))
                || (cmd.miss == CRS_INCLUDE
-                   && is_system_missing (&c->data[x->vars[j]->fv],
+                   && is_system_missing (case_data (c, x->vars[j]->fv),
                                           x->vars[j])))
              {
                x->missing += weight;
@@ -616,10 +587,10 @@ calc_general (struct ccase *c, void *aux UNUSED)
              }
              
            if (x->vars[j]->type == NUMERIC)
-             te->values[j].f = c->data[x->vars[j]->fv].f;
+             te->values[j].f = case_num (c, x->vars[j]->fv);
            else
              {
-               memcpy (te->values[j].s, c->data[x->vars[j]->fv].s,
+               memcpy (te->values[j].s, case_str (c, x->vars[j]->fv),
                         x->vars[j]->width);
              
                /* Necessary in order to simplify comparisons. */
@@ -656,8 +627,10 @@ calc_general (struct ccase *c, void *aux UNUSED)
 static int
 calc_integer (struct ccase *c, void *aux UNUSED)
 {
+  int bad_warn = 1;
+
   /* Case weight. */
-  double weight = dict_get_case_weight (default_dict, c);
+  double weight = dict_get_case_weight (default_dict, c, &bad_warn);
   
   /* Flattened current table index. */
   int t;
@@ -672,10 +645,11 @@ calc_integer (struct ccase *c, void *aux UNUSED)
       for (i = 0; i < x->nvar; i++)
        {
          struct variable *const v = x->vars[i];
-         double value = c->data[v->fv].f;
+          struct var_range *vr = get_var_range (v);
+         double value = case_num (c, v->fv);
          
          /* Note that the first test also rules out SYSMIS. */
-         if ((value < v->p.crs.min || value >= v->p.crs.max)
+         if ((value < vr->min || value >= vr->max)
              || (cmd.miss == CRS_TABLE && is_num_user_missing (value, v)))
            {
              x->missing += weight;
@@ -684,15 +658,19 @@ calc_integer (struct ccase *c, void *aux UNUSED)
          
          if (i > 1)
            {
-             ofs += fact * ((int) value - v->p.crs.min);
-             fact *= v->p.crs.count;
+             ofs += fact * ((int) value - vr->min);
+             fact *= vr->count;
            }
        }
       
       {
-       const int row = c->data[x->vars[ROW_VAR]->fv].f - x->vars[ROW_VAR]->p.crs.min;
-       const int col = c->data[x->vars[COL_VAR]->fv].f - x->vars[COL_VAR]->p.crs.min;
-       const int col_dim = x->vars[COL_VAR]->p.crs.count;
+        struct variable *row_var = x->vars[ROW_VAR];
+       const int row = case_num (c, row_var->fv) - get_var_range (row_var)->min;
+
+        struct variable *col_var = x->vars[COL_VAR];
+       const int col = case_num (c, col_var->fv) - 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;
       }
@@ -703,36 +681,6 @@ calc_integer (struct ccase *c, void *aux UNUSED)
   return 1;
 }
 
-#if DEBUGGING
-/* Print out all table entries in NULL-terminated TAB for use by a
-   debugger (a person, not a program). */
-static void
-print_table_entries (struct table_entry **tab)
-{
-  printf ("raw crosstabulation data:\n");
-  for (; *tab; tab++)
-    {
-      const struct crosstab *x = xtab[(*tab)->table];
-      int i;
-
-      printf ("(%g) table:%d ", (*tab)->u.freq, (*tab)->table);
-      for (i = 0; i < x->nvar; i++)
-       {
-         if (i)
-           printf (", ");
-         printf ("%s:", x->v[i]->name);
-         
-         if (x->v[i]->type == NUMERIC)
-           printf ("%g", (*tab)->v[i].f);
-         else
-           printf ("%.*s", x->v[i]->width, (*tab)->v[i].s);
-       }
-      printf ("\n");
-    }
-  fflush (stdout);
-}
-#endif
-
 /* Compare the table_entry's at A and B and return a strcmp()-type
    result. */
 static int 
@@ -808,9 +756,6 @@ postcalc (void *aux UNUSED)
     {
       n_sorted_tab = hsh_count (gen_tab);
       sorted_tab = (struct table_entry **) hsh_sort (gen_tab);
-#if DEBUGGING
-      print_table_entries (sorted_tab);
-#endif
     }
   
   make_summary_table ();
@@ -894,8 +839,8 @@ make_summary_table (void)
       else
        {
          const struct crosstab *const x = xtab[(*pb)->table];
-         const int n_cols = x->vars[COL_VAR]->p.crs.count;
-         const int n_rows = x->vars[ROW_VAR]->p.crs.count;
+         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++)
@@ -1394,35 +1339,6 @@ output_pivot_table (struct table_entry **pb, struct table_entry **pe,
        W = cum;
       }
       
-#if DEBUGGING
-      /* Print the matrix. */
-      {
-       int i, r, c;
-
-       printf ("%s by %s for", x->v[0]->name, x->v[1]->name);
-       for (i = 2; i < nvar; i++)
-         printf (" %s=%g", x->v[i]->name, tb[0]->v[i].f);
-       printf ("\n");
-       printf ("     ");
-       for (c = 0; c < n_cols; c++)
-         printf ("%4g", cols[c].f);
-       printf ("\n");
-       for (r = 0; r < n_rows; r++)
-         {
-           printf ("%4g:", rows[r].f);
-           for (c = 0; c < n_cols; c++)
-             printf ("%4g", mat[c + r * n_cols]);
-           printf ("%4g", row_tot[r]);
-           printf ("\n");
-         }
-       printf ("     ");
-       for (c = 0; c < n_cols; c++)
-         printf ("%4g", col_tot[c]);
-       printf ("%4g", W);
-       printf ("\n\n");
-      }
-#endif
-
       /* Find the first variable that differs from the last subtable,
         then display the values of the dimensioning variables for
         each table that needs it. */
@@ -1688,7 +1604,7 @@ compare_value (const void *a_, const void *b_, void *width_)
 
 /* Given an array of ENTRY_CNT table_entry structures starting at
    ENTRIES, creates a sorted list of the values that the variable
-   with index VAR_INDEX takes on.  The values are returned as a
+   with index VAR_IDX takes on.  The values are returned as a
    malloc()'darray stored in *VALUES, with the number of values
    stored in *VALUE_CNT.
    */
@@ -1696,9 +1612,11 @@ 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];
+
   if (mode == GENERAL)
     {
-      int width = xtab[(*entries)->table]->vars[var_idx]->width;
+      int width = v->width;
       int i;
 
       *values = xmalloc (sizeof **values * entry_cnt);
@@ -1709,15 +1627,14 @@ enum_var_values (struct table_entry **entries, int entry_cnt, int var_idx,
     }
   else
     {
-      struct crosstab_proc *crs
-        = &xtab[(*entries)->table]->vars[var_idx]->p.crs;
+      struct var_range *vr = get_var_range (v);
       int i;
       
       assert (mode == INTEGER);
-      *values = xmalloc (sizeof **values * crs->count);
-      for (i = 0; i < crs->count; i++)
-       (*values)[i].f = i + crs->min;
-      *value_cnt = crs->count;
+      *values = xmalloc (sizeof **values * vr->count);
+      for (i = 0; i < vr->count; i++)
+       (*values)[i].f = i + vr->min;
+      *value_cnt = vr->count;
     }
 }
 
@@ -1728,7 +1645,7 @@ static void
 table_value_missing (struct tab_table *table, int c, int r, unsigned char opt,
                     const union value *v, const struct variable *var)
 {
-  struct len_string s;
+  struct fixed_string s;
 
   const char *label = val_labs_find (var->val_labs, *v);
   if (label) 
@@ -1775,7 +1692,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 len_string s;
+  struct fixed_string s;
   
   s.length = 10;
   s.string = tab_alloc (table, 16);