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:
#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"
+/* (headers) */
+
#include "debug-print.h"
/* (specification)
crosstabs (crs_):
- *tables=custom;
+ *^tables=custom;
+variables=custom;
+missing=miss:!table/include/report;
+write[wr_]=none,cells,all;
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
{
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)
if (!parse_crosstabs (&cmd))
return CMD_FAILURE;
-#if DEBUGGING
- /* Needs variables. */
- debug_print ();
-#endif
-
mode = variables ? INTEGER : GENERAL;
/* CELLS. */
}
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 == '/')
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. */
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;
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);
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);
}
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;
}
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. */
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;
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;
}
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
{
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 ();
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++)
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. */
/* 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.
*/
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);
}
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;
}
}
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)
{
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);