src/data/calendar.h \
src/data/case-map.c \
src/data/case-map.h \
- src/data/case-ordering.c \
- src/data/case-ordering.h \
src/data/case.c \
src/data/casegrouper.c \
src/data/casegrouper.h \
src/data/short-names.h \
src/data/sparse-cases.c \
src/data/sparse-cases.h \
+ src/data/subcase.c \
+ src/data/subcase.h \
src/data/sys-file-private.c \
src/data/sys-file-private.h \
src/data/sys-file-reader.c \
+++ /dev/null
-/* PSPP - a program for statistical analysis.
- Copyright (C) 2007 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 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.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#include <config.h>
-
-#include <data/case-ordering.h>
-
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <data/dictionary.h>
-#include <data/variable.h>
-
-#include "xalloc.h"
-
-/* One key used for sorting. */
-struct sort_key
- {
- const struct variable *var; /* Variable. */
- enum sort_direction dir; /* Sort direction. */
- };
-
-/* A set of criteria for ordering cases. */
-struct case_ordering
- {
- /* Sort keys. */
- struct sort_key *keys;
- size_t key_cnt;
- };
-
-/* Creates and returns a new case ordering for comparing cases
- that represent dictionary DICT. The case ordering initially
- contains no variables, so that all cases will compare as
- equal. */
-struct case_ordering *
-case_ordering_create (void)
-{
- struct case_ordering *co = xmalloc (sizeof *co);
- co->keys = NULL;
- co->key_cnt = 0;
- return co;
-}
-
-/* Creates and returns a clone of case ordering ORIG. */
-struct case_ordering *
-case_ordering_clone (const struct case_ordering *orig)
-{
- struct case_ordering *co = xmalloc (sizeof *co);
- co->keys = xmemdup (orig->keys, orig->key_cnt * sizeof *orig->keys);
- co->key_cnt = orig->key_cnt;
- return co;
-}
-
-/* Destroys case ordering CO. */
-void
-case_ordering_destroy (struct case_ordering *co)
-{
- if (co != NULL)
- {
- free (co->keys);
- free (co);
- }
-}
-
-/* Compares cases A and B given case ordering CO and returns a
- strcmp()-type result. */
-int
-case_ordering_compare_cases (const struct ccase *a, const struct ccase *b,
- const struct case_ordering *co)
-{
- size_t i;
-
- for (i = 0; i < co->key_cnt; i++)
- {
- const struct sort_key *key = &co->keys[i];
- int width = var_get_width (key->var);
- int cmp;
-
- if (width == 0)
- {
- double af = case_num (a, key->var);
- double bf = case_num (b, key->var);
- if (af == bf)
- continue;
- cmp = af > bf ? 1 : -1;
- }
- else
- {
- const char *as = case_str (a, key->var);
- const char *bs = case_str (b, key->var);
- cmp = memcmp (as, bs, width);
- if (cmp == 0)
- continue;
- }
-
- return key->dir == SRT_ASCEND ? cmp : -cmp;
- }
- return 0;
-}
-
-/* Adds VAR to case ordering CO as an additional sort key in sort
- direction DIR. Returns true if successful, false if VAR was
- already part of the ordering for CO. */
-bool
-case_ordering_add_var (struct case_ordering *co,
- const struct variable *var, enum sort_direction dir)
-{
- struct sort_key *key;
- size_t i;
-
- for (i = 0; i < co->key_cnt; i++)
- if (var_get_case_index (co->keys[i].var) == var_get_case_index (var))
- return false;
-
- co->keys = xnrealloc (co->keys, co->key_cnt + 1, sizeof *co->keys);
- key = &co->keys[co->key_cnt++];
- key->var = var;
- key->dir = dir;
- return true;
-}
-
-/* Returns the number of variables used for ordering within
- CO. */
-size_t
-case_ordering_get_var_cnt (const struct case_ordering *co)
-{
- return co->key_cnt;
-}
-
-/* Returns sort variable IDX within CO. An IDX of 0 returns the
- primary sort key (the one added first), an IDX of 1 returns
- the secondary sort key, and so on. IDX must be less than the
- number of sort variables. */
-const struct variable *
-case_ordering_get_var (const struct case_ordering *co, size_t idx)
-{
- assert (idx < co->key_cnt);
- return co->keys[idx].var;
-}
-
-/* Returns the sort direction for sort variable IDX within CO. */
-enum sort_direction
-case_ordering_get_direction (const struct case_ordering *co, size_t idx)
-{
- assert (idx < co->key_cnt);
- return co->keys[idx].dir;
-}
-
-/* Stores an array listing all of the variables used for sorting
- within CO into *VARS and the number of variables into
- *VAR_CNT. The caller is responsible for freeing *VARS when it
- is no longer needed. */
-void
-case_ordering_get_vars (const struct case_ordering *co,
- const struct variable ***vars, size_t *var_cnt)
-{
- size_t i;
-
- *var_cnt = co->key_cnt;
- *vars = xnmalloc (*var_cnt, sizeof **vars);
- for (i = 0; i < co->key_cnt; i++)
- (*vars)[i] = co->keys[i].var;
-}
-
+++ /dev/null
-/* PSPP - a program for statistical analysis.
- Copyright (C) 2007 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 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.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-/* Sort order for comparing cases. */
-
-#ifndef DATA_CASE_ORDERING_H
-#define DATA_CASE_ORDERING_H 1
-
-#include <stddef.h>
-#include <data/case.h>
-
-struct dictionary;
-
-/* Sort direction. */
-enum sort_direction
- {
- SRT_ASCEND, /* A, B, C, ..., X, Y, Z. */
- SRT_DESCEND /* Z, Y, X, ..., C, B, A. */
- };
-
-/* Creation and destruction. */
-struct case_ordering *case_ordering_create (void);
-struct case_ordering *case_ordering_clone (const struct case_ordering *);
-void case_ordering_destroy (struct case_ordering *);
-
-/* Modification. */
-bool case_ordering_add_var (struct case_ordering *,
- const struct variable *, enum sort_direction);
-
-/* Comparing cases. */
-int case_ordering_compare_cases (const struct ccase *, const struct ccase *,
- const struct case_ordering *);
-
-/* Inspection. */
-size_t case_ordering_get_value_cnt (const struct case_ordering *);
-size_t case_ordering_get_var_cnt (const struct case_ordering *);
-const struct variable *case_ordering_get_var (const struct case_ordering *,
- size_t);
-enum sort_direction case_ordering_get_direction (const struct case_ordering *,
- size_t);
-void case_ordering_get_vars (const struct case_ordering *,
- const struct variable ***, size_t *);
-
-#endif /* data/case-ordering.h */
#include <stdlib.h>
-#include <data/case-ordering.h>
#include <data/casereader.h>
#include <data/casewriter.h>
#include <data/dictionary.h>
+#include <data/subcase.h>
#include <libpspp/taint.h>
#include "xalloc.h"
/* Casegrouper based on equal values of variables from case to
case. */
-/* Casegrouper based on equal variables. */
-struct casegrouper_vars
- {
- const struct variable **vars; /* Variables to compare. */
- size_t var_cnt; /* Number of variables. */
- };
-
static bool casegrouper_vars_same_group (const struct ccase *,
const struct ccase *,
void *);
const struct variable *const *vars,
size_t var_cnt)
{
- if (var_cnt > 0)
+ if (var_cnt > 0)
{
- struct casegrouper_vars *cv = xmalloc (sizeof *cv);
- cv->vars = xmemdup (vars, sizeof *vars * var_cnt);
- cv->var_cnt = var_cnt;
- return casegrouper_create_func (reader,
- casegrouper_vars_same_group,
- casegrouper_vars_destroy,
- cv);
+ struct subcase *sc = xmalloc (sizeof *sc);
+ subcase_init_vars (sc, vars, var_cnt);
+ return casegrouper_create_func (reader, casegrouper_vars_same_group,
+ casegrouper_vars_destroy, sc);
}
else
return casegrouper_create_func (reader, NULL, NULL, NULL);
/* Creates and returns a casegrouper that reads data from READER
and breaks it into contiguous groups of cases that have equal
- values for the variables used for sorting in CO. If CO is
- empty (contains no sort keys), then all the cases will be put
+ values for the variables used for sorting in SC. If SC is
+ empty (contains no fields), then all the cases will be put
into a single group. */
struct casegrouper *
-casegrouper_create_case_ordering (struct casereader *reader,
- const struct case_ordering *co)
+casegrouper_create_subcase (struct casereader *reader,
+ const struct subcase *sc)
{
- const struct variable **vars;
- size_t var_cnt;
- struct casegrouper *grouper;
-
- case_ordering_get_vars (co, &vars, &var_cnt);
- grouper = casegrouper_create_vars (reader, vars, var_cnt);
- free (vars);
-
- return grouper;
+ if (subcase_get_n_fields (sc) > 0)
+ {
+ struct subcase *sc_copy = xmalloc (sizeof *sc);
+ subcase_clone (sc_copy, sc);
+ return casegrouper_create_func (reader, casegrouper_vars_same_group,
+ casegrouper_vars_destroy, sc_copy);
+ }
+ else
+ return casegrouper_create_func (reader, NULL, NULL, NULL);
}
/* "same_group" function for an equal-variables casegrouper. */
static bool
casegrouper_vars_same_group (const struct ccase *a, const struct ccase *b,
- void *cv_)
+ void *sc_)
{
- struct casegrouper_vars *cv = cv_;
- return case_compare (a, b, cv->vars, cv->var_cnt) == 0;
+ struct subcase *sc = sc_;
+ return subcase_equal (sc, a, sc, b);
}
/* "destroy" for an equal-variables casegrouper. */
static void
-casegrouper_vars_destroy (void *cv_)
+casegrouper_vars_destroy (void *sc_)
{
- struct casegrouper_vars *cv = cv_;
- free (cv->vars);
- free (cv);
+ struct subcase *sc = sc_;
+ if (sc != NULL)
+ {
+ subcase_destroy (sc);
+ free (sc);
+ }
}
-
#include <stdbool.h>
#include <stddef.h>
-struct case_ordering;
struct casereader;
struct ccase;
struct dictionary;
+struct subcase;
struct variable;
struct casegrouper *
size_t var_cnt);
struct casegrouper *casegrouper_create_splits (struct casereader *,
const struct dictionary *);
-struct casegrouper *casegrouper_create_case_ordering (struct casereader *,
- const struct case_ordering *);
+struct casegrouper *casegrouper_create_subcase (struct casereader *,
+ const struct subcase *);
bool casegrouper_get_next_group (struct casegrouper *, struct casereader **);
bool casegrouper_destroy (struct casegrouper *);
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2008 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 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+#include <data/subcase.h>
+#include <stdlib.h>
+#include <data/case.h>
+#include <data/variable.h>
+#include <libpspp/assertion.h>
+
+#include "xalloc.h"
+
+/* Initializes SC as a subcase that contains no fields. */
+void
+subcase_init_empty (struct subcase *sc)
+{
+ sc->fields = NULL;
+ sc->n_fields = 0;
+ sc->n_values = 0;
+}
+
+/* Initializes SC as a subcase with fields extracted from the
+ N_VARS variables in VARS, with ascending sort order. */
+void
+subcase_init_vars (struct subcase *sc,
+ const struct variable *const *vars, size_t n_vars)
+{
+ size_t i;
+
+ sc->fields = xnmalloc (n_vars, sizeof *sc->fields);
+ sc->n_fields = n_vars;
+ sc->n_values = 0;
+ for (i = 0; i < n_vars; i++)
+ {
+ struct subcase_field *field = &sc->fields[i];
+ field->case_index = var_get_case_index (vars[i]);
+ field->width = var_get_width (vars[i]);
+ field->direction = SC_ASCEND;
+ sc->n_values += value_cnt_from_width (field->width);
+ }
+}
+
+/* Initializes SC as a subcase with a single field extracted
+ from VAR, with the sort order specified by DIRECTION. */
+void
+subcase_init_var (struct subcase *sc, const struct variable *var,
+ enum subcase_direction direction)
+{
+ subcase_init_empty (sc);
+ subcase_add_var (sc, var, direction);
+}
+
+/* Removes all the fields from SC. */
+void
+subcase_clear (struct subcase *sc)
+{
+ sc->n_fields = 0;
+ sc->n_values = 0;
+}
+
+/* Initializes SC with the same fields as ORIG. */
+void
+subcase_clone (struct subcase *sc, const struct subcase *orig)
+{
+ sc->fields = xmemdup (orig->fields, orig->n_fields * sizeof *orig->fields);
+ sc->n_fields = orig->n_fields;
+ sc->n_values = orig->n_values;
+}
+
+/* Frees the memory owned by SC (but not SC itself). */
+void
+subcase_destroy (struct subcase *sc)
+{
+ free (sc->fields);
+}
+
+/* Add a field for VAR to SC, with DIRECTION as the sort order.
+ Returns true if successful, false if VAR already has a field
+ in SC. */
+bool
+subcase_add_var (struct subcase *sc, const struct variable *var,
+ enum subcase_direction direction)
+{
+ size_t case_index = var_get_case_index (var);
+ struct subcase_field *field;
+ size_t i;
+
+ for (i = 0; i < sc->n_fields; i++)
+ if (sc->fields[i].case_index == case_index)
+ return false;
+
+ sc->fields = xnrealloc (sc->fields, sc->n_fields + 1, sizeof *sc->fields);
+ field = &sc->fields[sc->n_fields++];
+ field->case_index = case_index;
+ field->width = var_get_width (var);
+ field->direction = direction;
+ sc->n_values += value_cnt_from_width (field->width);
+ return true;
+}
+
+/* Returns true if and only if A and B are conformable, which
+ means that they have the same number of fields and that each
+ corresponding field in A and B have the same width. */
+bool
+subcase_conformable (const struct subcase *a, const struct subcase *b)
+{
+ size_t i;
+
+ if (a == b)
+ return true;
+ if (a->n_values != b->n_values || a->n_fields != b->n_fields)
+ return false;
+ for (i = 0; i < a->n_fields; i++)
+ if (a->fields[i].width != b->fields[i].width)
+ return false;
+ return true;
+}
+
+/* Copies the fields represented by SC from C into VALUES.
+ VALUES must have space for at least subcase_get_n_values(SC)
+ array elements. */
+void
+subcase_extract (const struct subcase *sc, const struct ccase *c,
+ union value values[])
+{
+ size_t i;
+
+ for (i = 0; i < sc->n_fields; i++)
+ {
+ const struct subcase_field *field = &sc->fields[i];
+ value_copy (values, case_data_idx (c, field->case_index), field->width);
+ values += value_cnt_from_width (field->width);
+ }
+}
+
+/* Copies the data in VALUES into the fields in C represented by
+ SC. VALUES must have at least subcase_get_n_values(SC) array
+ elements, and C must be large enough to contain all the fields
+ in SC. */
+void
+subcase_inject (const struct subcase *sc,
+ const union value values[], struct ccase *c)
+{
+ size_t i;
+
+ for (i = 0; i < sc->n_fields; i++)
+ {
+ const struct subcase_field *field = &sc->fields[i];
+ value_copy (case_data_rw_idx (c, field->case_index), values,
+ field->width);
+ values += value_cnt_from_width (field->width);
+ }
+}
+
+/* Copies the fields in SRC represented by SRC_SC into the
+ corresponding fields in DST respresented by DST_SC. SRC_SC
+ and DST_SC must be conformable (as tested by
+ subcase_conformable()). */
+void
+subcase_copy (const struct subcase *src_sc, const struct ccase *src,
+ const struct subcase *dst_sc, struct ccase *dst)
+{
+ size_t i;
+
+ expensive_assert (subcase_conformable (src_sc, dst_sc));
+ for (i = 0; i < src_sc->n_fields; i++)
+ {
+ const struct subcase_field *src_field = &src_sc->fields[i];
+ const struct subcase_field *dst_field = &dst_sc->fields[i];
+ value_copy (case_data_rw_idx (dst, dst_field->case_index),
+ case_data_idx (src, src_field->case_index),
+ src_field->width);
+ }
+}
+
+/* Compares the fields in A specified in A_SC against the fields
+ in B specified in B_SC. Returns -1, 0, or 1 if A's fields are
+ lexicographically less than, equal to, or greater than B's
+ fields, respectively.
+
+ A_SC and B_SC must be conformable (as tested by
+ subcase_conformable()). */
+int
+subcase_compare_3way (const struct subcase *a_sc, const struct ccase *a,
+ const struct subcase *b_sc, const struct ccase *b)
+{
+ size_t i;
+
+ expensive_assert (subcase_conformable (a_sc, b_sc));
+ for (i = 0; i < a_sc->n_fields; i++)
+ {
+ const struct subcase_field *a_field = &a_sc->fields[i];
+ const struct subcase_field *b_field = &b_sc->fields[i];
+ int cmp = value_compare_3way (case_data_idx (a, a_field->case_index),
+ case_data_idx (b, b_field->case_index),
+ a_field->width);
+ if (cmp != 0)
+ return a_field->direction == SC_ASCEND ? cmp : -cmp;
+ }
+ return 0;
+}
+
+/* Compares the values in A against the values in B specified by
+ SC's fields. Returns -1, 0, or 1 if A's values are
+ lexicographically less than, equal to, or greater than B's
+ values, respectively. */
+int
+subcase_compare_3way_xc (const struct subcase *sc,
+ const union value a[], const struct ccase *b)
+{
+ size_t i;
+
+ for (i = 0; i < sc->n_fields; i++)
+ {
+ const struct subcase_field *field = &sc->fields[i];
+ int cmp = value_compare_3way (a, case_data_idx (b, field->case_index),
+ field->width);
+ if (cmp != 0)
+ return field->direction == SC_ASCEND ? cmp : -cmp;
+ a += value_cnt_from_width (field->width);
+ }
+ return 0;
+}
+
+/* Compares the values in A specified by SC's fields against the
+ values in B. Returns -1, 0, or 1 if A's values are
+ lexicographically less than, equal to, or greater than B's
+ values, respectively. */
+int
+subcase_compare_3way_cx (const struct subcase *sc,
+ const struct ccase *a, const union value b[])
+{
+ return -subcase_compare_3way_xc (sc, b, a);
+}
+
+/* Compares the values in A against the values in B, using SC to
+ obtain the number and width of each value. Returns -1, 0, or
+ 1 if A's values are lexicographically less than, equal to, or
+ greater than B's values, respectively. */
+int
+subcase_compare_3way_xx (const struct subcase *sc,
+ const union value a[], const union value b[])
+{
+ size_t i;
+
+ for (i = 0; i < sc->n_fields; i++)
+ {
+ const struct subcase_field *field = &sc->fields[i];
+ size_t n_values;
+ int cmp;
+
+ cmp = value_compare_3way (a, b, field->width);
+ if (cmp != 0)
+ return field->direction == SC_ASCEND ? cmp : -cmp;
+
+ n_values = value_cnt_from_width (field->width);
+ a += n_values;
+ b += n_values;
+ }
+ return 0;
+}
+
+/* Compares the fields in A specified in A_SC against the fields
+ in B specified in B_SC. Returns true if the fields' values
+ are equal, false otherwise.
+
+ A_SC and B_SC must be conformable (as tested by
+ subcase_conformable()). */
+bool
+subcase_equal (const struct subcase *a_sc, const struct ccase *a,
+ const struct subcase *b_sc, const struct ccase *b)
+{
+ return subcase_compare_3way (a_sc, a, b_sc, b) == 0;
+}
+
+/* Compares the values in A against the values in B specified by
+ SC's fields. Returns true if A's values are equal to B's
+ values, otherwise false. */
+bool
+subcase_equal_xc (const struct subcase *sc,
+ const union value a[], const struct ccase *b)
+{
+ return subcase_compare_3way_xc (sc, a, b) == 0;
+}
+
+/* Compares the values in A specified by SC's fields against the
+ values in B. Returns true if A's values are equal to B's
+ values, otherwise false. */
+bool
+subcase_equal_cx (const struct subcase *sc,
+ const struct ccase *a, const union value b[])
+{
+ return subcase_compare_3way_cx (sc, a, b) == 0;
+}
+
+/* Compares the values in A against the values in B, using SC to
+ obtain the number and width of each value. Returns true if
+ A's values are equal to B's values, otherwise false. */
+bool
+subcase_equal_xx (const struct subcase *sc,
+ const union value a[], const union value b[])
+{
+ return subcase_compare_3way_xx (sc, a, b) == 0;
+}
+
--- /dev/null
+/* PSPP - a program for statistical analysis.
+ Copyright (C) 2008 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 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef DATA_SUBCASE_H
+#define DATA_SUBCASE_H 1
+
+#include <stdbool.h>
+#include <stddef.h>
+
+struct ccase;
+union value;
+struct variable;
+
+/* Sort order. */
+enum subcase_direction
+ {
+ SC_ASCEND, /* A, B, C, ..., X, Y, Z. */
+ SC_DESCEND /* Z, Y, X, ..., C, B, A. */
+ };
+
+/* A value within a case. */
+struct subcase_field
+ {
+ size_t case_index; /* Starting position in the case. */
+ int width; /* 0=numeric, otherwise string width. */
+ enum subcase_direction direction; /* Sort order. */
+ };
+
+/* A subcase specifies how to draw values from a case. */
+struct subcase
+ {
+ struct subcase_field *fields;
+ size_t n_fields;
+ size_t n_values;
+ };
+
+void subcase_init_empty (struct subcase *);
+void subcase_init_vars (struct subcase *,
+ const struct variable *const *, size_t n_vars);
+void subcase_init_var (struct subcase *,
+ const struct variable *, enum subcase_direction);
+void subcase_clone (struct subcase *, const struct subcase *);
+void subcase_clear (struct subcase *);
+void subcase_destroy (struct subcase *);
+
+bool subcase_add_var (struct subcase *, const struct variable *,
+ enum subcase_direction);
+
+static inline bool subcase_is_empty (const struct subcase *);
+static inline size_t subcase_get_n_fields (const struct subcase *);
+static inline size_t subcase_get_n_values (const struct subcase *);
+
+static inline enum subcase_direction subcase_get_direction (
+ const struct subcase *, size_t idx);
+
+bool subcase_conformable (const struct subcase *, const struct subcase *);
+
+void subcase_extract (const struct subcase *, const struct ccase *,
+ union value *values);
+void subcase_inject (const struct subcase *,
+ const union value *values, struct ccase *);
+void subcase_copy (const struct subcase *src_sc, const struct ccase *src,
+ const struct subcase *dst_sc, struct ccase *dst);
+
+int subcase_compare_3way (const struct subcase *a_sc, const struct ccase *a,
+ const struct subcase *b_sc, const struct ccase *b);
+int subcase_compare_3way_xc (const struct subcase *,
+ const union value *a, const struct ccase *b);
+int subcase_compare_3way_cx (const struct subcase *,
+ const struct ccase *a, const union value *b);
+int subcase_compare_3way_xx (const struct subcase *,
+ const union value *a, const union value *b);
+bool subcase_equal (const struct subcase *a_sc, const struct ccase *a,
+ const struct subcase *b_sc, const struct ccase *b);
+bool subcase_equal_xc (const struct subcase *,
+ const union value *a, const struct ccase *b);
+bool subcase_equal_cx (const struct subcase *,
+ const struct ccase *a, const union value *b);
+bool subcase_equal_xx (const struct subcase *,
+ const union value *a, const union value *b);
+
+static inline enum subcase_direction
+subcase_get_direction (const struct subcase *sc, size_t idx)
+{
+ return sc->fields[idx].direction;
+}
+
+static inline bool
+subcase_is_empty (const struct subcase *sc)
+{
+ return sc->n_fields == 0;
+}
+
+static inline size_t
+subcase_get_n_fields (const struct subcase *sc)
+{
+ return sc->n_fields;
+}
+
+static inline size_t
+subcase_get_n_values (const struct subcase *sc)
+{
+ return sc->n_values;
+}
+
+#endif /* data/subcase.h */
#include <stdlib.h>
#include <data/any-writer.h>
-#include <data/case-ordering.h>
#include <data/case.h>
#include <data/casegrouper.h>
#include <data/casereader.h>
#include <data/format.h>
#include <data/procedure.h>
#include <data/settings.h>
+#include <data/subcase.h>
#include <data/sys-file-writer.h>
#include <data/variable.h>
#include <language/command.h>
struct agr_proc
{
/* Break variables. */
- struct case_ordering *sort; /* Sort criteria (break variable). */
+ struct subcase sort; /* Sort criteria (break variables). */
const struct variable **break_vars; /* Break variables. */
size_t break_var_cnt; /* Number of break variables. */
struct ccase break_case; /* Last values of break variables. */
agr.dict = dict_create ();
agr.src_dict = dict;
+ subcase_init_empty (&agr.sort);
dict_set_label (agr.dict, dict_get_label (dict));
dict_set_documents (agr.dict, dict_get_documents (dict));
int i;
lex_match (lexer, '=');
- agr.sort = parse_case_ordering (lexer, dict,
-
- &saw_direction);
- if (agr.sort == NULL)
+ if (!parse_sort_criteria (lexer, dict, &agr.sort, &agr.break_vars,
+ &saw_direction))
goto error;
- case_ordering_get_vars (agr.sort,
- &agr.break_vars, &agr.break_var_cnt);
+ agr.break_var_cnt = subcase_get_n_fields (&agr.sort);
for (i = 0; i < agr.break_var_cnt; i++)
dict_clone_var_assert (agr.dict, agr.break_vars[i],
}
input = proc_open (ds);
- if (agr.sort != NULL && !presorted)
+ if (!subcase_is_empty (&agr.sort) && !presorted)
{
- input = sort_execute (input, agr.sort);
- agr.sort = NULL;
+ input = sort_execute (input, &agr.sort);
+ subcase_clear (&agr.sort);
}
for (grouper = casegrouper_create_vars (input, agr.break_vars,
{
struct agr_var *iter, *next;
- case_ordering_destroy (agr->sort);
+ subcase_destroy (&agr->sort);
free (agr->break_vars);
case_destroy (&agr->break_case);
for (iter = agr->agr_vars; iter; iter = next)
break;
case MEDIAN:
{
- struct case_ordering *ordering = case_ordering_create ();
+ struct subcase ordering;
if ( ! iter->subject)
iter->subject = var_create_internal (0);
if ( ! iter->weight)
iter->weight = var_create_internal (1);
- case_ordering_add_var (ordering, iter->subject, SRT_ASCEND);
+ subcase_init_var (&ordering, iter->subject, SC_ASCEND);
+ iter->writer = sort_create_writer (&ordering, 2);
+ subcase_destroy (&ordering);
- iter->writer = sort_create_writer (ordering, 2);
iter->cc = 0;
}
break;
#include <data/casegrouper.h>
#include <data/casereader.h>
#include <data/casewriter.h>
-#include <data/case-ordering.h>
#include <data/dictionary.h>
#include <data/procedure.h>
+#include <data/subcase.h>
#include <data/value-labels.h>
#include <data/variable.h>
#include <language/command.h>
{
/* In this case, we need to sort the data, so we create a sorting
casewriter */
- struct case_ordering *up_ordering = case_ordering_create ();
-
- case_ordering_add_var (up_ordering, dependent_vars[v], SRT_ASCEND);
- writer = sort_create_writer (up_ordering,
+ struct subcase up_ordering;
+ subcase_init_var (&up_ordering, dependent_vars[v], SC_ASCEND);
+ writer = sort_create_writer (&up_ordering,
casereader_get_value_cnt (reader));
+ subcase_destroy (&up_ordering);
}
else
{
struct casereader *group = NULL;
struct casereader *level1;
struct casegrouper *grouper1 = NULL;
- struct case_ordering *ordering1 = case_ordering_create ();
- case_ordering_add_var (ordering1, factor->indep_var[0], SRT_ASCEND);
level1 = casereader_clone (input);
-
- level1 = sort_execute (level1,
- case_ordering_clone (ordering1));
- grouper1 = casegrouper_create_case_ordering (level1, ordering1);
- case_ordering_destroy (ordering1);
+ level1 = sort_execute_1var (level1, factor->indep_var[0]);
+ grouper1 = casegrouper_create_vars (level1, &factor->indep_var[0], 1);
while (casegrouper_get_next_group (grouper1, &group))
{
int n_groups = 0;
struct casereader *group2 = NULL;
struct casegrouper *grouper2 = NULL;
- struct case_ordering *ordering2 = case_ordering_create ();
- case_ordering_add_var (ordering2,
- factor->indep_var[1], SRT_ASCEND);
- group_copy = sort_execute (group_copy,
- case_ordering_clone (ordering2));
- grouper2 =
- casegrouper_create_case_ordering (group_copy, ordering2);
+ group_copy = sort_execute_1var (group_copy,
+ factor->indep_var[1]);
- case_ordering_destroy (ordering2);
+ grouper2 = casegrouper_create_vars (group_copy,
+ &factor->indep_var[1], 1);
while (casegrouper_get_next_group (grouper2, &group2))
{
#include <limits.h>
#include <math.h>
-#include <data/case-ordering.h>
#include <data/case.h>
#include <data/casegrouper.h>
#include <data/casereader.h>
#include <data/missing-values.h>
#include <data/procedure.h>
#include <data/short-names.h>
+#include <data/subcase.h>
#include <data/variable.h>
#include <language/command.h>
#include <language/stats/sort-criteria.h>
static struct rank_spec *rank_specs;
static size_t n_rank_specs;
-static struct case_ordering *sc;
+static struct subcase sc;
static const struct variable **group_vars;
static size_t n_group_vars;
static bool
-rank_cmd (struct dataset *ds, const struct case_ordering *sc,
+rank_cmd (struct dataset *ds, const struct subcase *sc,
const struct rank_spec *rank_specs, int n_rank_specs)
{
struct dictionary *d = dataset_dict (ds);
bool ok = true;
int i;
- for (i = 0 ; i < case_ordering_get_var_cnt (sc) ; ++i )
+ for (i = 0 ; i < subcase_get_n_fields (sc) ; ++i )
{
/* Rank variable at index I in SC. */
struct casegrouper *split_grouper;
while (casegrouper_get_next_group (split_grouper, &split_group))
{
- struct case_ordering *ordering;
+ struct subcase ordering;
struct casereader *ordered;
struct casegrouper *by_grouper;
struct casereader *by_group;
- int j;
/* Sort this split group by the BY variables as primary
keys and the rank variable as secondary key. */
- ordering = case_ordering_create ();
- for (j = 0; j < n_group_vars; j++)
- case_ordering_add_var (ordering, group_vars[j], SRT_ASCEND);
- case_ordering_add_var (ordering,
- case_ordering_get_var (sc, i),
- case_ordering_get_direction (sc, i));
- ordered = sort_execute (split_group, ordering);
+ subcase_init_vars (&ordering, group_vars, n_group_vars);
+ subcase_add_var (&ordering, src_vars[i],
+ subcase_get_direction (sc, i));
+ ordered = sort_execute (split_group, &ordering);
+ subcase_destroy (&ordering);
/* Rank the rank variable within this split group. */
by_grouper = casegrouper_create_vars (ordered,
rank_specs = NULL;
n_rank_specs = 0;
- case_ordering_destroy (sc);
- sc = NULL;
+ subcase_destroy (&sc);
free (src_vars);
src_vars = NULL;
size_t i;
n_rank_specs = 0;
+ subcase_init_empty (&sc);
if ( !parse_rank (lexer, ds, &cmd, NULL) )
{
rank_cleanup ();
rank_specs = xmalloc (sizeof (*rank_specs));
rank_specs[0].rfunc = RANK;
rank_specs[0].destvars =
- xcalloc (case_ordering_get_var_cnt (sc), sizeof (struct variable *));
+ xcalloc (subcase_get_n_fields (&sc), sizeof (struct variable *));
n_rank_specs = 1;
}
- assert ( case_ordering_get_var_cnt (sc) == n_src_vars);
+ assert ( subcase_get_n_fields (&sc) == n_src_vars);
/* Create variables for all rank destinations which haven't
already been created with INTO.
add_transformation (ds, create_resort_key, 0, order);
/* Do the ranking */
- result = rank_cmd (ds, sc, rank_specs, n_rank_specs);
+ result = rank_cmd (ds, &sc, rank_specs, n_rank_specs);
/* Put the active file back in its original order. Delete
our sort key, which we don't need anymore. */
{
- struct case_ordering *ordering = case_ordering_create ();
struct casereader *sorted;
- case_ordering_add_var (ordering, order, SRT_ASCEND);
+
/* FIXME: loses error conditions. */
+
proc_discard_output (ds);
- sorted = sort_execute (proc_open (ds), ordering);
+ sorted = sort_execute_1var (proc_open (ds), order);
result = proc_commit (ds) && result;
dict_delete_var (dataset_dict (ds), order);
&& lex_token (lexer) != T_ALL)
return 2;
- sc = parse_case_ordering (lexer, dataset_dict (ds), NULL);
- if (sc == NULL)
+ if (!parse_sort_criteria (lexer, dataset_dict (ds), &sc, &src_vars, NULL))
return 0;
- case_ordering_get_vars (sc, &src_vars, &n_src_vars);
+ n_src_vars = subcase_get_n_fields (&sc);
if ( lex_match (lexer, T_BY) )
{
rank_specs[n_rank_specs - 1].destvars = NULL;
rank_specs[n_rank_specs - 1].destvars =
- xcalloc (case_ordering_get_var_cnt (sc),
- sizeof (struct variable *));
+ xcalloc (subcase_get_n_fields (&sc), sizeof (struct variable *));
if (lex_match_id (lexer, "INTO"))
{
msg(SE, _("Variable %s already exists."), lex_tokid (lexer));
return 0;
}
- if ( var_count >= case_ordering_get_var_cnt (sc) )
+ if ( var_count >= subcase_get_n_fields (&sc) )
{
msg(SE, _("Too many variables in INTO clause."));
return 0;
#include <language/command.h>
#include <language/lexer/lexer.h>
#include <libpspp/message.h>
-#include <data/case-ordering.h>
+#include <data/subcase.h>
#include <math/sort.h>
#include <sys/types.h>
int
cmd_sort_cases (struct lexer *lexer, struct dataset *ds)
{
- struct case_ordering *ordering;
+ struct subcase ordering;
struct casereader *output;
bool ok = false;
lex_match (lexer, T_BY);
proc_cancel_temporary_transformations (ds);
- ordering = parse_case_ordering (lexer, dataset_dict (ds), NULL);
- if (ordering == NULL)
+ subcase_init_empty (&ordering);
+ if (!parse_sort_criteria (lexer, dataset_dict (ds), &ordering, NULL, NULL))
return CMD_CASCADING_FAILURE;
if (settings_get_testing_mode () && lex_match (lexer, '/'))
}
proc_discard_output (ds);
- output = sort_execute (proc_open (ds), ordering);
- ordering = NULL;
+ output = sort_execute (proc_open (ds), &ordering);
ok = proc_commit (ds);
ok = proc_set_active_file_data (ds, output) && ok;
min_buffers = 64;
max_buffers = INT_MAX;
- case_ordering_destroy (ordering);
+ subcase_destroy (&ordering);
return ok ? lex_end_of_command (lexer) : CMD_CASCADING_FAILURE;
}
#include <stdlib.h>
-#include <data/case-ordering.h>
#include <data/dictionary.h>
+#include <data/subcase.h>
#include <data/variable.h>
#include <language/lexer/lexer.h>
#include <language/lexer/variable-parser.h>
#include "gettext.h"
#define _(msgid) gettext (msgid)
-/* Parses a list of sort keys and returns a struct sort_criteria
- based on it. Returns a null pointer on error.
+/* Parses a list of sort fields and appends them to ORDERING,
+ which the caller must already have initialized.
+ Returns true if successful, false on error.
If SAW_DIRECTION is nonnull, sets *SAW_DIRECTION to true if at
least one parenthesized sort direction was specified, false
otherwise. */
-struct case_ordering *
-parse_case_ordering (struct lexer *lexer, const struct dictionary *dict,
- bool *saw_direction)
+bool
+parse_sort_criteria (struct lexer *lexer, const struct dictionary *dict,
+ struct subcase *ordering,
+ const struct variable ***vars, bool *saw_direction)
{
- struct case_ordering *ordering = case_ordering_create ();
- const struct variable **vars = NULL;
+ const struct variable **local_vars = NULL;
size_t var_cnt = 0;
- if (saw_direction != NULL)
+ if (vars == NULL)
+ vars = &local_vars;
+ *vars = NULL;
+
+ if (saw_direction != NULL)
*saw_direction = false;
do
{
- enum sort_direction direction;
+ size_t prev_var_cnt = var_cnt;
+ enum subcase_direction direction;
size_t i;
/* Variables. */
- free (vars);
- vars = NULL;
- if (!parse_variables_const (lexer, dict, &vars, &var_cnt, PV_NO_SCRATCH))
+ if (!parse_variables_const (lexer, dict, vars, &var_cnt,
+ PV_APPEND | PV_NO_SCRATCH))
goto error;
/* Sort direction. */
if (lex_match (lexer, '('))
{
if (lex_match_id (lexer, "D") || lex_match_id (lexer, "DOWN"))
- direction = SRT_DESCEND;
+ direction = SC_DESCEND;
else if (lex_match_id (lexer, "A") || lex_match_id (lexer, "UP"))
- direction = SRT_ASCEND;
+ direction = SC_ASCEND;
else
{
msg (SE, _("`A' or `D' expected inside parentheses."));
*saw_direction = true;
}
else
- direction = SRT_ASCEND;
-
- for (i = 0; i < var_cnt; i++)
- if (!case_ordering_add_var (ordering, vars[i], direction))
- msg (SW, _("Variable %s specified twice in sort criteria."),
- var_get_name (vars[i]));
+ direction = SC_ASCEND;
+
+ for (i = prev_var_cnt; i < var_cnt; i++)
+ {
+ const struct variable *var = (*vars)[i];
+ if (!subcase_add_var (ordering, var, direction))
+ msg (SW, _("Variable %s specified twice in sort criteria."),
+ var_get_name (var));
+ }
}
while (lex_token (lexer) == T_ID
&& dict_lookup_var (dict, lex_tokid (lexer)) != NULL);
- free (vars);
- return ordering;
+ free (local_vars);
+ return true;
- error:
- free (vars);
- case_ordering_destroy (ordering);
- return NULL;
+error:
+ free (local_vars);
+ if (vars)
+ *vars = NULL;
+ return false;
}
struct dictionary;
struct lexer;
+struct variable;
+struct subcase;
-struct case_ordering *parse_case_ordering (struct lexer *,
- const struct dictionary *,
- bool *saw_direction);
+bool parse_sort_criteria (struct lexer *, const struct dictionary *,
+ struct subcase *, const struct variable ***vars,
+ bool *saw_direction);
-#endif /* SORT_PRS_H */
+#endif /* sort-criteria.h */
#include <data/variable.h>
#include <data/casereader.h>
#include <data/casewriter.h>
-#include <data/case-ordering.h>
+#include <data/subcase.h>
#include <math/sort.h>
#include <libpspp/message.h>
#include <xalloc.h>
struct casereader *r = casereader_clone (input);
struct casewriter *writer;
struct ccase c;
- struct case_ordering *ordering = case_ordering_create ();
+ struct subcase ordering;
variable_pair *vp = &t2s->pairs[i];
const int reader_width = weight ? 3 : 2;
ws[i].sign = var_create_internal (0);
ws[i].absdiff = var_create_internal (1);
- case_ordering_add_var (ordering, ws[i].absdiff, SRT_ASCEND);
-
-
r = casereader_create_filter_missing (r, *vp, 2,
exclude,
NULL, NULL);
- writer = sort_create_writer (ordering, reader_width);
+ subcase_init_var (&ordering, ws[i].absdiff, SC_ASCEND);
+ writer = sort_create_writer (&ordering, reader_width);
+ subcase_destroy (&ordering);
+
while (casereader_read (r, &c))
{
struct ccase output;
#include <math/merge.h>
-#include <data/case-ordering.h>
#include <data/case.h>
#include <data/casereader.h>
#include <data/casewriter.h>
+#include <data/subcase.h>
#include <libpspp/array.h>
#include <libpspp/assertion.h>
#include <libpspp/taint.h>
struct merge
{
- struct case_ordering *ordering;
+ struct subcase ordering;
struct merge_input inputs[MAX_MERGE_ORDER];
size_t input_cnt;
size_t value_cnt;
static void do_merge (struct merge *m);
struct merge *
-merge_create (const struct case_ordering *ordering, size_t value_cnt)
+merge_create (const struct subcase *ordering, size_t value_cnt)
{
struct merge *m = xmalloc (sizeof *m);
- m->ordering = case_ordering_clone (ordering);
+ subcase_clone (&m->ordering, ordering);
m->input_cnt = 0;
m->value_cnt = value_cnt;
return m;
{
size_t i;
- case_ordering_destroy (m->ordering);
+ subcase_destroy (&m->ordering);
for (i = 0; i < m->input_cnt; i++)
casereader_destroy (m->inputs[i].reader);
free (m);
min = 0;
for (i = 1; i < m->input_cnt; i++)
- if (case_ordering_compare_cases (&m->inputs[i].c, &m->inputs[min].c,
- m->ordering) < 0)
+ if (subcase_compare_3way (&m->ordering, &m->inputs[i].c,
+ &m->ordering, &m->inputs[min].c) < 0)
min = i;
casewriter_write (w, &m->inputs[min].c);
#include <stdbool.h>
#include <stddef.h>
-struct case_ordering;
+struct subcase;
struct casereader;
-struct merge *merge_create (const struct case_ordering *, size_t);
+struct merge *merge_create (const struct subcase *, size_t);
void merge_destroy (struct merge *);
void merge_append (struct merge *, struct casereader *);
struct casereader *merge_make_reader (struct merge *);
#include <stdio.h>
-#include <data/case-ordering.h>
#include <data/case.h>
#include <data/casereader.h>
#include <data/casewriter.h>
#include <data/casewriter-provider.h>
#include <data/settings.h>
+#include <data/subcase.h>
#include <libpspp/array.h>
#include <libpspp/assertion.h>
#include <math/merge.h>
struct sort_writer
{
size_t value_cnt;
- struct case_ordering *ordering;
+ struct subcase ordering;
struct merge *merge;
struct pqueue *pqueue;
static struct casewriter_class sort_casewriter_class;
-static struct pqueue *pqueue_create (const struct case_ordering *, size_t);
+static struct pqueue *pqueue_create (const struct subcase *, size_t);
static void pqueue_destroy (struct pqueue *);
static bool pqueue_is_full (const struct pqueue *);
static bool pqueue_is_empty (const struct pqueue *);
static void output_record (struct sort_writer *);
struct casewriter *
-sort_create_writer (struct case_ordering *ordering, size_t value_cnt)
+sort_create_writer (const struct subcase *ordering, size_t value_cnt)
{
struct sort_writer *sort;
sort = xmalloc (sizeof *sort);
sort->value_cnt = value_cnt;
- sort->ordering = case_ordering_clone (ordering);
+ subcase_clone (&sort->ordering, ordering);
sort->merge = merge_create (ordering, value_cnt);
sort->pqueue = pqueue_create (ordering, value_cnt);
sort->run = NULL;
sort->run_id = 0;
case_nullify (&sort->run_end);
- case_ordering_destroy (ordering);
-
return casewriter_create (value_cnt, &sort_casewriter_class, sort);
}
output_record (sort);
next_run = (case_is_null (&sort->run_end)
- || case_ordering_compare_cases (c, &sort->run_end,
- sort->ordering) < 0);
+ || subcase_compare_3way (&sort->ordering, c,
+ &sort->ordering, &sort->run_end) < 0);
pqueue_push (sort->pqueue, c, sort->run_id + (next_run ? 1 : 0));
}
{
struct sort_writer *sort = sort_;
- case_ordering_destroy (sort->ordering);
+ subcase_destroy (&sort->ordering);
merge_destroy (sort->merge);
pqueue_destroy (sort->pqueue);
casewriter_destroy (sort->run);
};
\f
/* Reads all the cases from INPUT. Sorts the cases according to
- ORDERING. Returns the sorted cases in a new casereader, or a
- null pointer if an I/O error occurs. Both INPUT and ORDERING
- are destroyed upon return, regardless of success. */
+ ORDERING. Returns the sorted cases in a new casereader. */
struct casereader *
-sort_execute (struct casereader *input, struct case_ordering *ordering)
+sort_execute (struct casereader *input, const struct subcase *ordering)
{
struct casewriter *output =
sort_create_writer (ordering, casereader_get_value_cnt (input));
casereader_transfer (input, output);
return casewriter_make_reader (output);
}
+
+/* Reads all the cases from INPUT. Sorts the cases in ascending
+ order according to VARIABLE. Returns the sorted cases in a
+ new casereader. */
+struct casereader *
+sort_execute_1var (struct casereader *input, const struct variable *var)
+{
+ struct subcase sc;
+ struct casereader *reader;
+
+ subcase_init_var (&sc, var, SC_ASCEND);
+ reader = sort_execute (input, &sc);
+ subcase_destroy (&sc);
+ return reader;
+}
\f
struct pqueue
{
- struct case_ordering *ordering;
+ struct subcase ordering;
struct pqueue_record *records;
size_t record_cnt;
size_t record_cap;
const void *pq_);
static struct pqueue *
-pqueue_create (const struct case_ordering *ordering, size_t value_cnt)
+pqueue_create (const struct subcase *ordering, size_t value_cnt)
{
struct pqueue *pq;
pq = xmalloc (sizeof *pq);
- pq->ordering = case_ordering_clone (ordering);
+ subcase_clone (&pq->ordering, ordering);
pq->record_cap
= settings_get_workspace_cases (value_cnt);
if (pq->record_cap > max_buffers)
pqueue_pop (pq, &c, &id);
case_destroy (&c);
}
- case_ordering_destroy (pq->ordering);
+ subcase_destroy (&pq->ordering);
free (pq->records);
free (pq);
}
const struct pqueue *pq = pq_;
int result = a->id < b->id ? -1 : a->id > b->id;
if (result == 0)
- result = case_ordering_compare_cases (&a->c, &b->c, pq->ordering);
+ result = subcase_compare_3way (&pq->ordering, &a->c,
+ &pq->ordering, &b->c);
if (result == 0)
result = a->idx < b->idx ? -1 : a->idx > b->idx;
return -result;
#include <stddef.h>
#include <stdbool.h>
-struct case_ordering;
+struct subcase;
+struct variable;
extern int min_buffers ;
extern int max_buffers ;
-struct casewriter *sort_create_writer (struct case_ordering *, size_t value_cnt);
-struct casereader *sort_execute (struct casereader *, struct case_ordering *);
+struct casewriter *sort_create_writer (const struct subcase *,
+ size_t value_cnt);
+struct casereader *sort_execute (struct casereader *, const struct subcase *);
+struct casereader *sort_execute_1var (struct casereader *,
+ const struct variable *);
#endif /* math/sort.h */
void
-psppire_case_file_sort (PsppireCaseFile *cf, struct case_ordering *ordering)
+psppire_case_file_sort (PsppireCaseFile *cf, const struct subcase *ordering)
{
struct casereader *sorted_data;
gint c;
gboolean psppire_case_file_insert_values (PsppireCaseFile *cf, gint n_values, gint where);
-struct case_ordering;
+struct subcase;
-void psppire_case_file_sort (PsppireCaseFile *cf, struct case_ordering *);
+void psppire_case_file_sort (PsppireCaseFile *cf, const struct subcase *);
gboolean psppire_case_file_get_case (const PsppireCaseFile *cf,
casenumber casenum,