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. */
#include <config.h>
#include "error.h"
#include <stdlib.h>
#include "alloc.h"
+#include "any-writer.h"
#include "case.h"
#include "casefile.h"
#include "command.h"
#include "pool.h"
#include "settings.h"
#include "sfm-write.h"
+#include "sort-prs.h"
#include "sort.h"
#include "str.h"
#include "var.h"
#include "vfm.h"
#include "vfmP.h"
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
/* Specifies how to make an aggregate variable. */
struct agr_var
{
struct agr_func
{
const char *name; /* Aggregation function name. */
- int n_args; /* Number of arguments. */
+ size_t n_args; /* Number of arguments. */
int alpha_type; /* When given ALPHA arguments, output type. */
struct fmt_spec format; /* Format spec if alpha_type != ALPHA. */
};
struct agr_proc
{
/* We have either an output file or a sink. */
- struct sfm_writer *writer; /* Output file, or null if none. */
+ struct any_writer *writer; /* Output file, or null if none. */
struct case_sink *sink; /* Sink, or null if none. */
/* Break variables. */
struct sort_criteria *sort; /* Sort criteria. */
struct variable **break_vars; /* Break variables. */
size_t break_var_cnt; /* Number of break variables. */
- union value *prev_break; /* Last values of break variables. */
+ struct ccase break_case; /* Last values of break variables. */
enum missing_treatment missing; /* How to treat missing values. */
struct agr_var *agr_vars; /* First aggregate variable. */
struct ccase agr_case; /* Aggregate case for output. */
};
-static void initialize_aggregate_info (struct agr_proc *);
+static void initialize_aggregate_info (struct agr_proc *,
+ const struct ccase *);
/* Prototypes. */
static int parse_aggregate_functions (struct agr_proc *);
memset(&agr, 0 , sizeof (agr));
agr.missing = ITEMWISE;
+ case_nullify (&agr.break_case);
agr.dict = dict_create ();
dict_set_label (agr.dict, dict_get_label (default_dict));
lex_match ('=');
if (!lex_match ('*'))
{
- out_file = fh_parse ();
+ out_file = fh_parse (FH_REF_FILE | FH_REF_SCRATCH);
if (out_file == NULL)
goto error;
}
lex_match ('=');
agr.sort = sort_parse_criteria (default_dict,
&agr.break_vars, &agr.break_var_cnt,
- &saw_direction);
+ &saw_direction, NULL);
if (agr.sort == NULL)
goto error;
for (i = 0; i < agr.break_var_cnt; i++)
- {
- struct variable *v = dict_clone_var (agr.dict, agr.break_vars[i],
- agr.break_vars[i]->name,
- agr.break_vars[i]->longname
- );
- assert (v != NULL);
- }
+ dict_clone_var_assert (agr.dict, agr.break_vars[i],
+ agr.break_vars[i]->name);
/* BREAK must follow the options. */
break;
/* Initialize. */
agr.case_cnt = 0;
case_create (&agr.agr_case, dict_get_next_value_idx (agr.dict));
- initialize_aggregate_info (&agr);
/* Output to active file or external file? */
if (out_file == NULL)
}
else
{
- agr.writer = sfm_open_writer (out_file, agr.dict, get_scompression (), 0);
+ agr.writer = any_writer_open (out_file, agr.dict);
if (agr.writer == NULL)
goto error;
while (casereader_read_xfer (reader, &c))
{
if (aggregate_single_case (&agr, &c, &agr.agr_case))
- sfm_write_case (agr.writer, &agr.agr_case);
+ any_writer_write (agr.writer, &agr.agr_case);
case_destroy (&c);
}
casereader_destroy (reader);
if (agr.case_cnt > 0)
{
dump_aggregate_info (&agr, &agr.agr_case);
- sfm_write_case (agr.writer, &agr.agr_case);
+ any_writer_write (agr.writer, &agr.agr_case);
}
}
{
char **dest;
char **dest_label;
- int n_dest;
+ size_t n_dest;
int include_missing;
const struct agr_func *function;
union value arg[2];
struct variable **src;
- int n_src;
+ size_t n_src;
- int i;
+ size_t i;
dest = NULL;
dest_label = NULL;
/* Parse the list of target variables. */
while (!lex_match ('='))
{
- int n_dest_prev = n_dest;
+ size_t n_dest_prev = n_dest;
if (!parse_DATA_LIST_vars (&dest, &n_dest,
PV_APPEND | PV_SINGLE | PV_NO_SCRATCH))
{
int j;
- dest_label = xrealloc (dest_label, sizeof *dest_label * n_dest);
+ dest_label = xnrealloc (dest_label, n_dest, sizeof *dest_label);
for (j = n_dest_prev; j < n_dest; j++)
dest_label[j] = NULL;
}
arg[i].f = tokval;
type = NUMERIC;
} else {
- msg (SE, _("Missing argument %d to %s."), i + 1, function->name);
+ msg (SE, _("Missing argument %d to %s."), i + 1,
+ function->name);
goto error;
}
like `unknown variable t'. */
if (n_src != n_dest)
{
- msg (SE, _("Number of source variables (%d) does not match "
- "number of target variables (%d)."),
- n_src, n_dest);
+ msg (SE, _("Number of source variables (%u) does not match "
+ "number of target variables (%u)."),
+ (unsigned) n_src, (unsigned) n_dest);
goto error;
}
|| func_index == FIN || func_index == FOUT)
&& ((src[0]->type == NUMERIC && arg[0].f > arg[1].f)
|| (src[0]->type == ALPHA
- && st_compare_pad (arg[0].c, strlen (arg[0].c),
- arg[1].c, strlen (arg[1].c)) > 0)))
+ && str_compare_rpad (arg[0].c, arg[1].c) > 0)))
{
union value t = arg[0];
arg[0] = arg[1];
/* Create the target variable in the aggregate
dictionary. */
{
- static const struct fmt_spec f8_2 = {FMT_F, 8, 2};
struct variable *destvar;
v->function = func_index;
}
if (function->alpha_type == ALPHA)
- destvar = dict_clone_var (agr->dict, v->src, 0, dest[i] );
- else if (v->src->type == NUMERIC
- || function->alpha_type == NUMERIC)
+ destvar = dict_clone_var (agr->dict, v->src, dest[i]);
+ else
{
+ assert (v->src->type == NUMERIC
+ || function->alpha_type == NUMERIC);
destvar = dict_create_var (agr->dict, dest[i], 0);
if (destvar != NULL)
{
{
struct agr_var *iter, *next;
- sfm_close_writer (agr->writer);
+ any_writer_close (agr->writer);
if (agr->sort != NULL)
sort_destroy_criteria (agr->sort);
free (agr->break_vars);
- free (agr->prev_break);
+ case_destroy (&agr->break_case);
for (iter = agr->agr_vars; iter; iter = next)
{
next = iter->next;
if (iter->function & FSTRING)
{
- int n_args;
- int i;
+ size_t n_args;
+ size_t i;
n_args = agr_func_tab[iter->function & FUNC].n_args;
for (i = 0; i < n_args; i++)
aggregate_single_case (struct agr_proc *agr,
const struct ccase *input, struct ccase *output)
{
- /* The first case always begins a new break group. We also need to
- preserve the values of the case for later comparison. */
+ bool finished_group = false;
+
if (agr->case_cnt++ == 0)
+ initialize_aggregate_info (agr, input);
+ else if (case_compare (&agr->break_case, input,
+ agr->break_vars, agr->break_var_cnt))
{
- int n_elem = 0;
-
- {
- int i;
+ dump_aggregate_info (agr, output);
+ finished_group = true;
- for (i = 0; i < agr->break_var_cnt; i++)
- n_elem += agr->break_vars[i]->nv;
- }
-
- agr->prev_break = xmalloc (sizeof *agr->prev_break * n_elem);
-
- /* Copy INPUT into prev_break. */
- {
- union value *iter = agr->prev_break;
- int i;
-
- for (i = 0; i < agr->break_var_cnt; i++)
- {
- struct variable *v = agr->break_vars[i];
-
- if (v->type == NUMERIC)
- (iter++)->f = case_num (input, v->fv);
- else
- {
- memcpy (iter->s, case_str (input, v->fv), v->width);
- iter += v->nv;
- }
- }
- }
-
- accumulate_aggregate_info (agr, input);
-
- return 0;
+ initialize_aggregate_info (agr, input);
}
-
- /* Compare the value of each break variable to the values on the
- previous case. */
- {
- union value *iter = agr->prev_break;
- int i;
-
- for (i = 0; i < agr->break_var_cnt; i++)
- {
- struct variable *v = agr->break_vars[i];
-
- switch (v->type)
- {
- case NUMERIC:
- if (case_num (input, v->fv) != iter->f)
- goto not_equal;
- iter++;
- break;
- case ALPHA:
- if (memcmp (case_str (input, v->fv), iter->s, v->width))
- goto not_equal;
- iter += v->nv;
- break;
- default:
- assert (0);
- }
- }
- }
-
- accumulate_aggregate_info (agr, input);
- return 0;
-
-not_equal:
- /* The values of the break variable are different from the values on
- the previous case. That means that it's time to dump aggregate
- info. */
- dump_aggregate_info (agr, output);
- initialize_aggregate_info (agr);
accumulate_aggregate_info (agr, input);
-
- /* Copy INPUT into prev_break. */
- {
- union value *iter = agr->prev_break;
- int i;
-
- for (i = 0; i < agr->break_var_cnt; i++)
- {
- struct variable *v = agr->break_vars[i];
-
- if (v->type == NUMERIC)
- (iter++)->f = case_num (input, v->fv);
- else
- {
- memcpy (iter->s, case_str (input, v->fv), v->width);
- iter += v->nv;
- }
- }
- }
-
- return 1;
+ return finished_group;
}
/* Accumulates aggregation data from the case INPUT. */
{
const union value *v = case_data (input, iter->src->fv);
- if ((!iter->include_missing && is_missing (v, iter->src))
+ if ((!iter->include_missing
+ && mv_is_value_missing (&iter->src->miss, v))
|| (iter->include_missing && iter->src->type == NUMERIC
&& v->f == SYSMIS))
{
for (i = 0; i < agr->break_var_cnt; i++)
{
- int nv = agr->break_vars[i]->nv;
+ struct variable *v = agr->break_vars[i];
memcpy (case_data_rw (output, value_idx),
- &agr->prev_break[value_idx],
- sizeof (union value) * nv);
- value_idx += nv;
+ case_data (&agr->break_case, v->fv),
+ sizeof (union value) * v->nv);
+ value_idx += v->nv;
}
}
/* Resets the state for all the aggregate functions. */
static void
-initialize_aggregate_info (struct agr_proc *agr)
+initialize_aggregate_info (struct agr_proc *agr, const struct ccase *input)
{
struct agr_var *iter;
+ case_destroy (&agr->break_case);
+ case_clone (&agr->break_case, input);
+
for (iter = agr->agr_vars; iter; iter = iter->next)
{
iter->missing = 0;
struct agr_proc *agr = agr_;
if (aggregate_single_case (agr, c, &agr->agr_case))
- sfm_write_case (agr->writer, &agr->agr_case);
+ any_writer_write (agr->writer, &agr->agr_case);
return 1;
}