/* PSPP - a program for statistical analysis.
- Copyright (C) 2007, 2009 Free Software Foundation, Inc.
+ Copyright (C) 2007, 2009, 2010, 2014 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
#include <data/datasheet.h>
#include <ctype.h>
+#include <float.h>
#include <stdlib.h>
+#include <stdint.h>
#include <string.h>
#include <data/casereader-provider.h>
#include "error.h"
#include "minmax.h"
#include "progname.h"
-#include "xalloc.h"
/* lazy_casereader callback function to instantiate a casereader
from the datasheet. */
int max_rows; /* Maximum number of rows. */
int max_cols; /* Maximum number of columns. */
int backing_rows; /* Number of rows of backing store. */
- int backing_cols; /* Number of columns of backing store. */
+ int backing_widths[MAX_COLS]; /* Widths of columns of backing store. */
+ int n_backing_cols; /* Number of columns of backing store. */
int widths[MAX_WIDTHS]; /* Allowed column widths. */
int n_widths;
/* State. */
- int next_value;
+ unsigned int next_value;
};
static bool
if (!check_caseproto (mc, proto, casereader_get_proto (reader),
"casereader"))
return;
- else if (casereader_get_case_cnt (reader) != n_rows)
+ else if (casereader_get_n_cases (reader) != n_rows)
{
- if (casereader_get_case_cnt (reader) == CASENUMBER_MAX
+ if (casereader_get_n_cases (reader) == CASENUMBER_MAX
&& casereader_count_cases (reader) == n_rows)
mc_error (mc, "datasheet casereader has unknown case count");
else
mc_error (mc, "casereader row count (%lu) does not match "
"expected (%zu)",
- (unsigned long int) casereader_get_case_cnt (reader),
+ (unsigned long int) casereader_get_n_cases (reader),
n_rows);
}
else
{
if (width == 0)
mc_error (mc, "element %zu,%zu (of %zu,%zu) differs: "
- "%g != %g",
+ "%.*g != %.*g",
row, col, n_rows, n_columns,
- case_num_idx (c, col), array[row][col].f);
+ DBL_DIG + 1, case_num_idx (c, col),
+ DBL_DIG + 1, array[row][col].f);
else
mc_error (mc, "element %zu,%zu (of %zu,%zu) differs: "
"'%.*s' != '%.*s'",
row, col, n_rows, n_columns,
width, case_str_idx (c, col),
- width, value_str (&array[row][col], width));
+ width, array[row][col].s);
}
}
{
if (width == 0)
mc_error (mc, "element %zu,%zu (of %zu,%zu) differs: "
- "%g != %g", row, col, n_rows, n_columns,
- v.f, av->f);
+ "%.*g != %.*g", row, col, n_rows, n_columns,
+ DBL_DIG + 1, v.f, DBL_DIG + 1, av->f);
else
mc_error (mc, "element %zu,%zu (of %zu,%zu) differs: "
"'%.*s' != '%.*s'",
row, col, n_rows, n_columns,
- width, value_str (&v, width),
- width, value_str (av, width));
+ width, v.s,
+ width, v.s);
difference = true;
}
value_destroy (&v, width);
if (width == 0)
ds_put_format (&s, " %g", v->f);
else
- ds_put_format (&s, " '%.*s'", width, value_str (v, width));
+ ds_put_format (&s, " '%.*s'", width, v->s);
}
mc_error (mc, "%s", ds_cstr (&s));
}
if (width == 0)
ds_put_format (&s, " %g", v.f);
else
- ds_put_format (&s, " '%.*s'",
- width, value_str (&v, width));
+ ds_put_format (&s, " '%.*s'", width, v.s);
}
mc_error (mc, "%s", ds_cstr (&s));
}
odata, data);
}
+static void
+value_from_param (union value *value, int width, unsigned int idx)
+{
+ if (width == 0)
+ value->f = idx & 0xffff;
+ else
+ {
+ unsigned int hash = hash_int (idx, 0);
+ int offset;
+
+ assert (width < 32);
+ for (offset = 0; offset < width; offset++)
+ value->s[offset] = "ABCDEFGHIJ"[(hash >> offset) % 10];
+ }
+}
+
/* "init" function for struct mc_class. */
static void
datasheet_mc_init (struct mc *mc)
struct datasheet_test_params *params = mc_get_aux (mc);
struct datasheet *ds;
- if (params->backing_rows == 0 && params->backing_cols == 0)
+ if (params->backing_rows == 0 && params->n_backing_cols == 0)
{
/* Create unbacked datasheet. */
+ struct caseproto *proto;
ds = datasheet_create (NULL);
mc_name_operation (mc, "empty datasheet");
- check_datasheet (mc, ds, NULL, 0, caseproto_create ());
+ proto = caseproto_create ();
+ check_datasheet (mc, ds, NULL, 0, proto);
+ caseproto_unref (proto);
}
else
{
int row, col;
assert (params->backing_rows > 0 && params->backing_rows <= MAX_ROWS);
- assert (params->backing_cols > 0 && params->backing_cols <= MAX_COLS);
+ assert (params->n_backing_cols > 0
+ && params->n_backing_cols <= MAX_COLS);
- /* XXX support different backing column widths */
proto = caseproto_create ();
- for (col = 0; col < params->backing_cols; col++)
- proto = caseproto_add_width (proto, 0);
+ for (col = 0; col < params->n_backing_cols; col++)
+ proto = caseproto_add_width (proto, params->backing_widths[col]);
writer = mem_writer_create (proto);
for (row = 0; row < params->backing_rows; row++)
struct ccase *c;
c = case_create (proto);
- for (col = 0; col < params->backing_cols; col++)
+ for (col = 0; col < params->n_backing_cols; col++)
{
- double value = params->next_value++;
- data[row][col].f = value;
- case_data_rw_idx (c, col)->f = value;
+ int width = params->backing_widths[col];
+ union value *value = &data[row][col];
+ value_init (value, width);
+ value_from_param (value, width, params->next_value++);
+ value_copy (case_data_rw_idx (c, col), value, width);
}
casewriter_write (writer, c);
}
- caseproto_unref (proto);
reader = casewriter_make_reader (writer);
assert (reader != NULL);
ds = datasheet_create (reader);
mc_name_operation (mc, "datasheet with (%d,%d) backing",
- params->backing_rows, params->backing_cols);
+ params->backing_rows, params->n_backing_cols);
check_datasheet (mc, ds, data,
params->backing_rows, proto);
+ release_data (params->backing_rows, proto, data);
+ caseproto_unref (proto);
}
}
+struct resize_cb_aux
+ {
+ int old_width;
+ int new_width;
+ };
+
static void
-value_from_param (union value *value, int width, int idx)
+resize_cb (const union value *old_value, union value *new_value, const void *aux_)
{
- if (width == 0)
- value->f = idx;
- else
- {
- unsigned int hash = hash_int (idx, 0);
- char *string = value_str_rw (value, width);
- int offset;
+ const struct resize_cb_aux *aux = aux_;
- assert (width < 32);
- for (offset = 0; offset < width; offset++)
- string[offset] = "ABCDEFGHIJ"[(hash >> offset) % 10];
- }
+ value_from_param (new_value, aux->new_width,
+ value_hash (old_value, aux->old_width, 0));
}
/* "mutate" function for struct mc_class. */
const struct caseproto *oproto = datasheet_get_proto (ods);
size_t n_columns = datasheet_get_n_columns (ods);
size_t n_rows = datasheet_get_n_rows (ods);
- size_t pos, new_pos, cnt, width_idx;
+ size_t pos, new_pos, n, width_idx;
extract_data (ods, odata);
caseproto_unref (proto);
}
+ /* Resize each column to each possible new size. */
+ for (pos = 0; pos < n_columns; pos++)
+ for (width_idx = 0; width_idx < params->n_widths; width_idx++)
+ {
+ int owidth = caseproto_get_width (oproto, pos);
+ int width = params->widths[width_idx];
+ if (mc_include_state (mc))
+ {
+ struct resize_cb_aux aux;
+ struct caseproto *proto;
+ struct datasheet *ds;
+ size_t i;
+
+ mc_name_operation (mc, "resize column %zu (of %zu) "
+ "from width %d to %d",
+ pos, n_columns, owidth, width);
+ clone_model (ods, odata, &ds, data);
+
+ aux.old_width = owidth;
+ aux.new_width = width;
+ if (!datasheet_resize_column (ds, pos, width, resize_cb, &aux))
+ NOT_REACHED ();
+ proto = caseproto_set_width (caseproto_ref (oproto), pos, width);
+
+ for (i = 0; i < n_rows; i++)
+ {
+ union value *old_value = &data[i][pos];
+ union value new_value;
+ value_init (&new_value, width);
+ resize_cb (old_value, &new_value, &aux);
+ value_swap (old_value, &new_value);
+ value_destroy (&new_value, owidth);
+ }
+
+ check_datasheet (mc, ds, data, n_rows, proto);
+ release_data (n_rows, proto, data);
+ caseproto_unref (proto);
+ }
+ }
+
/* Delete all possible numbers of columns from all possible
positions. */
for (pos = 0; pos < n_columns; pos++)
- for (cnt = 1; cnt < n_columns - pos; cnt++)
+ for (n = 1; n < n_columns - pos; n++)
if (mc_include_state (mc))
{
struct caseproto *proto;
mc_name_operation (mc, "delete %zu columns at %zu "
"(from %zu to %zu columns)",
- cnt, pos, n_columns, n_columns - cnt);
+ n, pos, n_columns, n_columns - n);
clone_model (ods, odata, &ds, data);
- datasheet_delete_columns (ds, pos, cnt);
- proto = caseproto_remove_widths (caseproto_ref (oproto), pos, cnt);
+ datasheet_delete_columns (ds, pos, n);
+ proto = caseproto_remove_widths (caseproto_ref (oproto), pos, n);
for (i = 0; i < n_rows; i++)
{
- for (j = pos; j < pos + cnt; j++)
+ for (j = pos; j < pos + n; j++)
value_destroy (&data[i][j], caseproto_get_width (oproto, j));
- remove_range (&data[i], n_columns, sizeof *data[i], pos, cnt);
+ remove_range (&data[i], n_columns, sizeof *data[i], pos, n);
}
check_datasheet (mc, ds, data, n_rows, proto);
/* Move all possible numbers of columns from all possible
existing positions to all possible new positions. */
for (pos = 0; pos < n_columns; pos++)
- for (cnt = 1; cnt < n_columns - pos; cnt++)
- for (new_pos = 0; new_pos < n_columns - cnt; new_pos++)
+ for (n = 1; n < n_columns - pos; n++)
+ for (new_pos = 0; new_pos < n_columns - n; new_pos++)
if (mc_include_state (mc))
{
struct caseproto *proto;
clone_model (ods, odata, &ds, data);
mc_name_operation (mc, "move %zu columns (of %zu) from %zu to %zu",
- cnt, n_columns, pos, new_pos);
+ n, n_columns, pos, new_pos);
- datasheet_move_columns (ds, pos, new_pos, cnt);
+ datasheet_move_columns (ds, pos, new_pos, n);
for (i = 0; i < n_rows; i++)
move_range (&data[i], n_columns, sizeof data[i][0],
- pos, new_pos, cnt);
+ pos, new_pos, n);
proto = caseproto_move_widths (caseproto_ref (oproto),
- pos, new_pos, cnt);
+ pos, new_pos, n);
check_datasheet (mc, ds, data, n_rows, proto);
release_data (n_rows, proto, data);
/* Insert all possible numbers of rows in all possible
positions. */
for (pos = 0; pos <= n_rows; pos++)
- for (cnt = 1; cnt <= params->max_rows - n_rows; cnt++)
+ for (n = 1; n <= params->max_rows - n_rows; n++)
if (mc_include_state (mc))
{
struct datasheet *ds;
clone_model (ods, odata, &ds, data);
mc_name_operation (mc, "insert %zu rows at %zu "
"(from %zu to %zu rows)",
- cnt, pos, n_rows, n_rows + cnt);
+ n, pos, n_rows, n_rows + n);
- for (i = 0; i < cnt; i++)
+ for (i = 0; i < n; i++)
{
c[i] = case_create (oproto);
for (j = 0; j < n_columns; j++)
params->next_value++);
}
- insert_range (data, n_rows, sizeof data[pos], pos, cnt);
- for (i = 0; i < cnt; i++)
+ insert_range (data, n_rows, sizeof data[pos], pos, n);
+ for (i = 0; i < n; i++)
for (j = 0; j < n_columns; j++)
{
int width = caseproto_get_width (oproto, j);
value_copy (&data[i + pos][j], case_data_idx (c[i], j), width);
}
- if (!datasheet_insert_rows (ds, pos, c, cnt))
+ if (!datasheet_insert_rows (ds, pos, c, n))
mc_error (mc, "datasheet_insert_rows failed");
- check_datasheet (mc, ds, data, n_rows + cnt, oproto);
- release_data (n_rows + cnt, oproto, data);
+ check_datasheet (mc, ds, data, n_rows + n, oproto);
+ release_data (n_rows + n, oproto, data);
}
/* Delete all possible numbers of rows from all possible
positions. */
for (pos = 0; pos < n_rows; pos++)
- for (cnt = 1; cnt < n_rows - pos; cnt++)
+ for (n = 1; n < n_rows - pos; n++)
if (mc_include_state (mc))
{
struct datasheet *ds;
clone_model (ods, odata, &ds, data);
mc_name_operation (mc, "delete %zu rows at %zu "
"(from %zu to %zu rows)",
- cnt, pos, n_rows, n_rows - cnt);
+ n, pos, n_rows, n_rows - n);
- datasheet_delete_rows (ds, pos, cnt);
+ datasheet_delete_rows (ds, pos, n);
- release_data (cnt, oproto, &data[pos]);
- remove_range (&data[0], n_rows, sizeof data[0], pos, cnt);
+ release_data (n, oproto, &data[pos]);
+ remove_range (&data[0], n_rows, sizeof data[0], pos, n);
- check_datasheet (mc, ds, data, n_rows - cnt, oproto);
- release_data (n_rows - cnt, oproto, data);
+ check_datasheet (mc, ds, data, n_rows - n, oproto);
+ release_data (n_rows - n, oproto, data);
}
/* Move all possible numbers of rows from all possible existing
positions to all possible new positions. */
for (pos = 0; pos < n_rows; pos++)
- for (cnt = 1; cnt < n_rows - pos; cnt++)
- for (new_pos = 0; new_pos < n_rows - cnt; new_pos++)
+ for (n = 1; n < n_rows - pos; n++)
+ for (new_pos = 0; new_pos < n_rows - n; new_pos++)
if (mc_include_state (mc))
{
struct datasheet *ds;
clone_model (ods, odata, &ds, data);
mc_name_operation (mc, "move %zu rows (of %zu) from %zu to %zu",
- cnt, n_rows, pos, new_pos);
+ n, n_rows, pos, new_pos);
- datasheet_move_rows (ds, pos, new_pos, cnt);
+ datasheet_move_rows (ds, pos, new_pos, n);
move_range (&data[0], n_rows, sizeof data[0],
- pos, new_pos, cnt);
+ pos, new_pos, n);
check_datasheet (mc, ds, data, n_rows, oproto);
release_data (n_rows, oproto, data);
OPT_MAX_ROWS,
OPT_MAX_COLUMNS,
OPT_BACKING_ROWS,
- OPT_BACKING_COLUMNS,
+ OPT_BACKING_WIDTHS,
OPT_WIDTHS,
OPT_HELP,
N_DATASHEET_OPTIONS
};
-static struct argv_option datasheet_argv_options[N_DATASHEET_OPTIONS] =
+static const struct argv_option datasheet_argv_options[N_DATASHEET_OPTIONS] =
{
{"max-rows", 0, required_argument, OPT_MAX_ROWS},
{"max-columns", 0, required_argument, OPT_MAX_COLUMNS},
{"backing-rows", 0, required_argument, OPT_BACKING_ROWS},
- {"backing-columns", 0, required_argument, OPT_BACKING_COLUMNS},
+ {"backing-widths", 0, required_argument, OPT_BACKING_WIDTHS},
{"widths", 0, required_argument, OPT_WIDTHS},
{"help", 'h', no_argument, OPT_HELP},
};
params->backing_rows = atoi (optarg);
break;
- case OPT_BACKING_COLUMNS:
- params->backing_cols = atoi (optarg);
+ case OPT_BACKING_WIDTHS:
+ {
+ char *w;
+
+ params->n_backing_cols = 0;
+ for (w = strtok (optarg, ", "); w != NULL; w = strtok (NULL, ", "))
+ {
+ int value = atoi (w);
+
+ if (params->n_backing_cols >= MAX_COLS)
+ error (1, 0, "Too many widths on --backing-widths "
+ "(only %d are allowed)", MAX_COLS);
+ if (!isdigit (w[0]) || value < 0 || value > 31)
+ error (1, 0, "--backing-widths argument must be a list of 1 to "
+ "%d integers between 0 and 31 in increasing order",
+ MAX_COLS);
+ params->backing_widths[params->n_backing_cols++] = value;
+ }
+ }
break;
case OPT_WIDTHS:
" --max-rows=N Maximum number of rows (0...5, 3)\n"
" --max-rows=N Maximum number of columns (0...5, 3)\n"
" --backing-rows=N Rows of backing store (0...max_rows, 0)\n"
- " --backing-columns=N Columns of backing store (0...max_cols, 0)\n"
+ " --backing-widths=W[,W]... Backing store widths to test (0=num)\n"
" --widths=W[,W]... Column widths to test, where 0=numeric,\n"
" other values are string widths (0,1,11)\n",
program_name, program_name);
mc_options_usage ();
- fputs ("\nOther options:\n"
- " --help Display this help message\n"
- "\nReport bugs to <bug-gnu-pspp@gnu.org>\n",
- stdout);
+ printf ("\nOther options:\n"
+ " --help Display this help message\n"
+ "\nReport bugs to <%s>\n", PACKAGE_BUGREPORT);
exit (0);
}
params.max_rows = 3;
params.max_cols = 3;
params.backing_rows = 0;
- params.backing_cols = 0;
+ params.n_backing_cols = 0;
params.widths[0] = 0;
params.widths[1] = 1;
params.widths[2] = 11;
params.n_widths = 3;
params.next_value = 1;
- /* Parse comand line. */
+ /* Parse command line. */
parser = argv_parser_create ();
options = mc_options_create ();
mc_options_register_argv_parser (options, parser);
params.max_rows = MIN (params.max_rows, MAX_ROWS);
params.max_cols = MIN (params.max_cols, MAX_COLS);
params.backing_rows = MIN (params.backing_rows, params.max_rows);
- params.backing_cols = MIN (params.backing_cols, params.max_cols);
+ params.n_backing_cols = MIN (params.n_backing_cols, params.max_cols);
mc_options_set_aux (options, ¶ms);
results = mc_run (&datasheet_mc_class, options);
{
int i;
- printf ("Parameters: "
- "--max-rows=%d --max-columns=%d "
- "--backing-rows=%d --backing-columns=%d ",
- params.max_rows, params.max_cols,
- params.backing_rows, params.backing_cols);
+ printf ("Parameters: --max-rows=%d --max-columns=%d --backing-rows=%d ",
+ params.max_rows, params.max_cols, params.backing_rows);
+
+ printf ("--backing-widths=");
+ for (i = 0; i < params.n_backing_cols; i++)
+ {
+ if (i > 0)
+ printf (",");
+ printf ("%d", params.backing_widths[i]);
+ }
+ printf (" ");
+
printf ("--widths=");
for (i = 0; i < params.n_widths; i++)
{