X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flanguage%2Fstats%2Faggregate.c;h=50a98e483efeed4ede0fa6336692b2e57e0394c3;hb=a45fa3f76f32c391c756b7e4334330458d74a1ab;hp=e1dcd12342ff2b42ff94dcbf472affeb58bb51c1;hpb=015e221b0f8578afee769528572c76387f26c629;p=pspp diff --git a/src/language/stats/aggregate.c b/src/language/stats/aggregate.c index e1dcd12342..50a98e483e 100644 --- a/src/language/stats/aggregate.c +++ b/src/language/stats/aggregate.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006, 2008 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2006, 2008, 2009, 2010 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 @@ -19,7 +19,6 @@ #include #include -#include #include #include #include @@ -29,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -46,11 +46,14 @@ #include #include +#include "aggregate.h" + #include "minmax.h" #include "xalloc.h" #include "gettext.h" #define _(msgid) gettext (msgid) +#define N_(msgid) msgid /* Argument for AGGREGATE function. */ union agr_argument @@ -84,52 +87,31 @@ struct agr_var struct casewriter *writer; }; -/* Aggregation functions. */ -enum - { - NONE, SUM, MEAN, MEDIAN, SD, MAX, MIN, PGT, PLT, PIN, POUT, FGT, FLT, FIN, - FOUT, N, NU, NMISS, NUMISS, FIRST, LAST, - N_AGR_FUNCS, N_NO_VARS, NU_NO_VARS, - FUNC = 0x1f, /* Function mask. */ - FSTRING = 1<<5, /* String function bit. */ - }; - -/* Attributes of an aggregation function. */ -struct agr_func - { - const char *name; /* Aggregation function name. */ - size_t n_args; /* Number of arguments. */ - enum val_type alpha_type; /* When given ALPHA arguments, output type. */ - struct fmt_spec format; /* Format spec if alpha_type != ALPHA. */ - }; /* Attributes of aggregation functions. */ -static const struct agr_func agr_func_tab[] = +const struct agr_func agr_func_tab[] = { - {"", 0, -1, {0, 0, 0}}, - {"SUM", 0, -1, {FMT_F, 8, 2}}, - {"MEAN", 0, -1, {FMT_F, 8, 2}}, - {"MEDIAN", 0, -1, {FMT_F, 8, 2}}, - {"SD", 0, -1, {FMT_F, 8, 2}}, - {"MAX", 0, VAL_STRING, {-1, -1, -1}}, - {"MIN", 0, VAL_STRING, {-1, -1, -1}}, - {"PGT", 1, VAL_NUMERIC, {FMT_F, 5, 1}}, - {"PLT", 1, VAL_NUMERIC, {FMT_F, 5, 1}}, - {"PIN", 2, VAL_NUMERIC, {FMT_F, 5, 1}}, - {"POUT", 2, VAL_NUMERIC, {FMT_F, 5, 1}}, - {"FGT", 1, VAL_NUMERIC, {FMT_F, 5, 3}}, - {"FLT", 1, VAL_NUMERIC, {FMT_F, 5, 3}}, - {"FIN", 2, VAL_NUMERIC, {FMT_F, 5, 3}}, - {"FOUT", 2, VAL_NUMERIC, {FMT_F, 5, 3}}, - {"N", 0, VAL_NUMERIC, {FMT_F, 7, 0}}, - {"NU", 0, VAL_NUMERIC, {FMT_F, 7, 0}}, - {"NMISS", 0, VAL_NUMERIC, {FMT_F, 7, 0}}, - {"NUMISS", 0, VAL_NUMERIC, {FMT_F, 7, 0}}, - {"FIRST", 0, VAL_STRING, {-1, -1, -1}}, - {"LAST", 0, VAL_STRING, {-1, -1, -1}}, - {NULL, 0, -1, {-1, -1, -1}}, - {"N", 0, VAL_NUMERIC, {FMT_F, 7, 0}}, - {"NU", 0, VAL_NUMERIC, {FMT_F, 7, 0}}, + {"SUM", N_("Sum of values"), AGR_SV_YES, 0, -1, {FMT_F, 8, 2}}, + {"MEAN", N_("Mean average"), AGR_SV_YES, 0, -1, {FMT_F, 8, 2}}, + {"MEDIAN", N_("Median average"), AGR_SV_YES, 0, -1, {FMT_F, 8, 2}}, + {"SD", N_("Standard deviation"), AGR_SV_YES, 0, -1, {FMT_F, 8, 2}}, + {"MAX", N_("Maximum value"), AGR_SV_YES, 0, VAL_STRING, {-1, -1, -1}}, + {"MIN", N_("Minimum value"), AGR_SV_YES, 0, VAL_STRING, {-1, -1, -1}}, + {"PGT", N_("Percentage greater than"), AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 1}}, + {"PLT", N_("Percentage less than"), AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 1}}, + {"PIN", N_("Percentage included in range"), AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 1}}, + {"POUT", N_("Percentage excluded from range"), AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 1}}, + {"FGT", N_("Fraction greater than"), AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 3}}, + {"FLT", N_("Fraction less than"), AGR_SV_YES, 1, VAL_NUMERIC, {FMT_F, 5, 3}}, + {"FIN", N_("Fraction included in range"), AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 3}}, + {"FOUT", N_("Fraction excluded from range"), AGR_SV_YES, 2, VAL_NUMERIC, {FMT_F, 5, 3}}, + {"N", N_("Number of cases"), AGR_SV_NO, 0, VAL_NUMERIC, {FMT_F, 7, 0}}, + {"NU", N_("Number of cases (unweighted)"), AGR_SV_OPT, 0, VAL_NUMERIC, {FMT_F, 7, 0}}, + {"NMISS", N_("Number of missing values"), AGR_SV_YES, 0, VAL_NUMERIC, {FMT_F, 7, 0}}, + {"NUMISS", N_("Number of missing values (unweighted)"), AGR_SV_YES, 0, VAL_NUMERIC, {FMT_F, 7, 0}}, + {"FIRST", N_("First non-missing value"), AGR_SV_YES, 0, VAL_STRING, {-1, -1, -1}}, + {"LAST", N_("Last non-missing value"), AGR_SV_YES, 0, VAL_STRING, {-1, -1, -1}}, + {NULL, NULL, AGR_SV_NO, 0, -1, {-1, -1, -1}}, }; /* Missing value types. */ @@ -143,20 +125,21 @@ enum missing_treatment 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. */ enum missing_treatment missing; /* How to treat missing values. */ struct agr_var *agr_vars; /* First aggregate variable. */ struct dictionary *dict; /* Aggregate dictionary. */ const struct dictionary *src_dict; /* Dict of the source */ int case_cnt; /* Counts aggregated cases. */ + + bool add_variables; /* True iff the aggregated variables should + be appended to the existing dictionary */ }; -static void initialize_aggregate_info (struct agr_proc *, - const struct ccase *); +static void initialize_aggregate_info (struct agr_proc *); static void accumulate_aggregate_info (struct agr_proc *, const struct ccase *); @@ -164,8 +147,9 @@ static void accumulate_aggregate_info (struct agr_proc *, static bool parse_aggregate_functions (struct lexer *, const struct dictionary *, struct agr_proc *); static void agr_destroy (struct agr_proc *); -static void dump_aggregate_info (struct agr_proc *agr, - struct casewriter *output); +static void dump_aggregate_info (const struct agr_proc *agr, + struct casewriter *output, + const struct ccase *break_case); /* Parsing. */ @@ -187,14 +171,11 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) memset(&agr, 0 , sizeof (agr)); agr.missing = ITEMWISE; - case_nullify (&agr.break_case); - - agr.dict = dict_create (); agr.src_dict = dict; - dict_set_label (agr.dict, dict_get_label (dict)); - dict_set_documents (agr.dict, dict_get_documents (dict)); + subcase_init_empty (&agr.sort); /* OUTFILE subcommand must be first. */ + lex_match (lexer, '/'); if (!lex_force_match_id (lexer, "OUTFILE")) goto error; lex_match (lexer, '='); @@ -205,6 +186,32 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) goto error; } + if (out_file == NULL && lex_match_id (lexer, "MODE")) + { + lex_match (lexer, '='); + if (lex_match_id (lexer, "ADDVARIABLES")) + { + agr.add_variables = true; + + /* presorted is assumed in ADDVARIABLES mode */ + presorted = true; + } + else if (lex_match_id (lexer, "REPLACE")) + { + agr.add_variables = false; + } + else + goto error; + } + + if ( agr.add_variables ) + agr.dict = dict_clone (dict); + else + agr.dict = dict_create (); + + dict_set_label (agr.dict, dict_get_label (dict)); + dict_set_documents (agr.dict, dict_get_documents (dict)); + /* Read most of the subcommands. */ for (;;) { @@ -215,7 +222,7 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) lex_match (lexer, '='); if (!lex_match_id (lexer, "COLUMNWISE")) { - lex_error (lexer, _("while expecting COLUMNWISE")); + lex_error (lexer, _("expecting %s"), "COLUMNWISE"); goto error; } agr.missing = COLUMNWISE; @@ -224,31 +231,26 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) copy_documents = true; else if (lex_match_id (lexer, "PRESORTED")) presorted = true; - else if (lex_match_id (lexer, "BREAK")) + else if (lex_force_match_id (lexer, "BREAK")) { 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], - var_get_name (agr.break_vars[i])); + if (! agr.add_variables) + for (i = 0; i < agr.break_var_cnt; i++) + dict_clone_var_assert (agr.dict, agr.break_vars[i]); /* BREAK must follow the options. */ break; } else - { - lex_error (lexer, _("expecting BREAK")); - goto error; - } + goto error; + } if (presorted && saw_direction) msg (SW, _("When PRESORTED is specified, specifying sorting directions " @@ -276,7 +278,7 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) so TEMPORARY is moot. */ proc_cancel_temporary_transformations (ds); proc_discard_output (ds); - output = autopaging_writer_create (dict_get_next_value_idx (agr.dict)); + output = autopaging_writer_create (dict_get_proto (agr.dict)); } else { @@ -286,10 +288,10 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) } 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, @@ -297,19 +299,40 @@ cmd_aggregate (struct lexer *lexer, struct dataset *ds) casegrouper_get_next_group (grouper, &group); casereader_destroy (group)) { - struct ccase c; + struct casereader *placeholder = NULL; + struct ccase *c = casereader_peek (group, 0); - if (!casereader_peek (group, 0, &c)) + if (c == NULL) { casereader_destroy (group); continue; } - initialize_aggregate_info (&agr, &c); - case_destroy (&c); - for (; casereader_read (group, &c); case_destroy (&c)) - accumulate_aggregate_info (&agr, &c); - dump_aggregate_info (&agr, output); + initialize_aggregate_info (&agr); + + if ( agr.add_variables ) + placeholder = casereader_clone (group); + + { + struct ccase *cg; + for (; (cg = casereader_read (group)) != NULL; case_unref (cg)) + accumulate_aggregate_info (&agr, cg); + } + + + if (agr.add_variables) + { + struct ccase *cg; + for (; (cg = casereader_read (placeholder)) != NULL; case_unref (cg)) + dump_aggregate_info (&agr, output, cg); + + casereader_destroy (placeholder); + } + else + { + dump_aggregate_info (&agr, output, c); + case_unref (c); + } } if (!casegrouper_destroy (grouper)) goto error; @@ -394,7 +417,8 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, size_t n_dest_prev = n_dest; if (!parse_DATA_LIST_vars (lexer, &dest, &n_dest, - PV_APPEND | PV_SINGLE | PV_NO_SCRATCH)) + (PV_APPEND | PV_SINGLE | PV_NO_SCRATCH + | PV_NO_DUPLICATE))) goto error; /* Assign empty labels. */ @@ -427,14 +451,8 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, goto error; } - exclude = MV_ANY; - ds_assign_string (&function_name, lex_tokstr (lexer)); - - ds_chomp (&function_name, '.'); - - if (lex_tokid(lexer)[strlen (lex_tokid (lexer)) - 1] == '.') - exclude = MV_SYSTEM; + exclude = ds_chomp (&function_name, '.') ? MV_SYSTEM : MV_ANY; for (function = agr_func_tab; function->name; function++) if (!strcasecmp (function->name, ds_cstr (&function_name))) @@ -452,13 +470,9 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, /* Check for leading lparen. */ if (!lex_match (lexer, '(')) { - if (func_index == N) - func_index = N_NO_VARS; - else if (func_index == NU) - func_index = NU_NO_VARS; - else + if (function->src_vars == AGR_SV_YES) { - lex_error (lexer, _("expecting `('")); + lex_force_match (lexer, '('); goto error; } } @@ -514,11 +528,8 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, } /* Trailing rparen. */ - if (!lex_match (lexer, ')')) - { - lex_error (lexer, _("expecting `)'")); - goto error; - } + if (!lex_force_match (lexer, ')')) + goto error; /* Now check that the number of source variables match the number of target variables. If we check earlier @@ -584,7 +595,7 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, } if (function->alpha_type == VAL_STRING) - destvar = dict_clone_var (agr->dict, v->src, dest[i]); + destvar = dict_clone_var_as (agr->dict, v->src, dest[i]); else { assert (var_is_numeric (v->src) @@ -605,12 +616,16 @@ parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, struct fmt_spec f; v->src = NULL; destvar = dict_create_var (agr->dict, dest[i], 0); - if (func_index == N_NO_VARS && dict_get_weight (dict) != NULL) - f = fmt_for_output (FMT_F, 8, 2); - else - f = function->format; - var_set_both_formats (destvar, &f); - } + if (destvar != NULL) + { + if ((func_index == N || func_index == NMISS) + && dict_get_weight (dict) != NULL) + f = fmt_for_output (FMT_F, 8, 2); + else + f = function->format; + var_set_both_formats (destvar, &f); + } + } if (!destvar) { @@ -694,9 +709,8 @@ agr_destroy (struct agr_proc *agr) { 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) { next = iter->next; @@ -714,8 +728,8 @@ agr_destroy (struct agr_proc *agr) else if (iter->function == SD) moments1_destroy (iter->moments); - var_destroy (iter->subject); - var_destroy (iter->weight); + dict_destroy_internal_var (iter->subject); + dict_destroy_internal_var (iter->weight); free (iter); } @@ -772,20 +786,20 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) case MEDIAN: { double wv ; - struct ccase cout; - case_create (&cout, 2); + struct ccase *cout; - case_data_rw (&cout, iter->subject)->f = - case_data (input, iter->src)->f; + cout = case_create (casewriter_get_proto (iter->writer)); + + case_data_rw (cout, iter->subject)->f + = case_data (input, iter->src)->f; wv = dict_get_case_weight (agr->src_dict, input, NULL); - case_data_rw (&cout, iter->weight)->f = wv; + case_data_rw (cout, iter->weight)->f = wv; iter->cc += wv; - casewriter_write (iter->writer, &cout); - case_destroy (&cout); + casewriter_write (iter->writer, cout); } break; case SD: @@ -796,8 +810,8 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) iter->int1 = 1; break; case MAX | FSTRING: - if (memcmp (iter->string, v->s, src_width) < 0) - memcpy (iter->string, v->s, src_width); + if (memcmp (iter->string, value_str (v, src_width), src_width) < 0) + memcpy (iter->string, value_str (v, src_width), src_width); iter->int1 = 1; break; case MIN: @@ -805,8 +819,8 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) iter->int1 = 1; break; case MIN | FSTRING: - if (memcmp (iter->string, v->s, src_width) > 0) - memcpy (iter->string, v->s, src_width); + if (memcmp (iter->string, value_str (v, src_width), src_width) > 0) + memcpy (iter->string, value_str (v, src_width), src_width); iter->int1 = 1; break; case FGT: @@ -817,7 +831,8 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) break; case FGT | FSTRING: case PGT | FSTRING: - if (memcmp (iter->arg[0].c, v->s, src_width) < 0) + if (memcmp (iter->arg[0].c, + value_str (v, src_width), src_width) < 0) iter->dbl[0] += weight; iter->dbl[1] += weight; break; @@ -829,7 +844,8 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) break; case FLT | FSTRING: case PLT | FSTRING: - if (memcmp (iter->arg[0].c, v->s, src_width) > 0) + if (memcmp (iter->arg[0].c, + value_str (v, src_width), src_width) > 0) iter->dbl[0] += weight; iter->dbl[1] += weight; break; @@ -841,8 +857,10 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) break; case FIN | FSTRING: case PIN | FSTRING: - if (memcmp (iter->arg[0].c, v->s, src_width) <= 0 - && memcmp (iter->arg[1].c, v->s, src_width) >= 0) + if (memcmp (iter->arg[0].c, + value_str (v, src_width), src_width) <= 0 + && memcmp (iter->arg[1].c, + value_str (v, src_width), src_width) >= 0) iter->dbl[0] += weight; iter->dbl[1] += weight; break; @@ -854,8 +872,10 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) break; case FOUT | FSTRING: case POUT | FSTRING: - if (memcmp (iter->arg[0].c, v->s, src_width) > 0 - || memcmp (iter->arg[1].c, v->s, src_width) < 0) + if (memcmp (iter->arg[0].c, + value_str (v, src_width), src_width) > 0 + || memcmp (iter->arg[1].c, + value_str (v, src_width), src_width) < 0) iter->dbl[0] += weight; iter->dbl[1] += weight; break; @@ -877,7 +897,7 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) case FIRST | FSTRING: if (iter->int1 == 0) { - memcpy (iter->string, v->s, src_width); + memcpy (iter->string, value_str (v, src_width), src_width); iter->int1 = 1; } break; @@ -886,7 +906,7 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) iter->int1 = 1; break; case LAST | FSTRING: - memcpy (iter->string, v->s, src_width); + memcpy (iter->string, value_str (v, src_width), src_width); iter->int1 = 1; break; case NMISS: @@ -899,13 +919,13 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) default: NOT_REACHED (); } - } else { + } else { switch (iter->function) { - case N_NO_VARS: + case N: iter->dbl[0] += weight; break; - case NU_NO_VARS: + case NU: iter->int1++; break; default: @@ -916,46 +936,43 @@ accumulate_aggregate_info (struct agr_proc *agr, const struct ccase *input) /* Writes an aggregated record to OUTPUT. */ static void -dump_aggregate_info (struct agr_proc *agr, struct casewriter *output) +dump_aggregate_info (const struct agr_proc *agr, struct casewriter *output, const struct ccase *break_case) { - struct ccase c; - - case_create (&c, dict_get_next_value_idx (agr->dict)); + struct ccase *c = case_create (dict_get_proto (agr->dict)); - { - int value_idx = 0; - int i; + if ( agr->add_variables) + { + case_copy (c, 0, break_case, 0, dict_get_var_cnt (agr->src_dict)); + } + else + { + int value_idx = 0; + int i; - for (i = 0; i < agr->break_var_cnt; i++) - { - const struct variable *v = agr->break_vars[i]; - size_t value_cnt = var_get_value_cnt (v); - memcpy (case_data_rw_idx (&c, value_idx), - case_data (&agr->break_case, v), - sizeof (union value) * value_cnt); - value_idx += value_cnt; - } - } + for (i = 0; i < agr->break_var_cnt; i++) + { + const struct variable *v = agr->break_vars[i]; + value_copy (case_data_rw_idx (c, value_idx), + case_data (break_case, v), + var_get_width (v)); + value_idx++; + } + } { struct agr_var *i; for (i = agr->agr_vars; i; i = i->next) { - union value *v = case_data_rw (&c, i->dest); - + union value *v = case_data_rw (c, i->dest); + int width = var_get_width (i->dest); if (agr->missing == COLUMNWISE && i->saw_missing && (i->function & FUNC) != N && (i->function & FUNC) != NU && (i->function & FUNC) != NMISS && (i->function & FUNC) != NUMISS) { - if (var_is_alpha (i->dest)) - memset (v->s, ' ', var_get_width (i->dest)); - else - v->f = SYSMIS; - + value_set_missing (v, width); casewriter_destroy (i->writer); - continue; } @@ -969,21 +986,22 @@ dump_aggregate_info (struct agr_proc *agr, struct casewriter *output) break; case MEDIAN: { - struct casereader *sorted_reader; - struct order_stats *median = percentile_create (0.5, i->cc); - - sorted_reader = casewriter_make_reader (i->writer); - - order_stats_accumulate (&median, 1, - sorted_reader, - i->weight, - i->subject, - i->exclude); - - v->f = percentile_calculate ((struct percentile *) median, - PC_HAVERAGE); - - statistic_destroy ((struct statistic *) median); + if ( i->writer) + { + struct percentile *median = percentile_create (0.5, i->cc); + struct order_stats *os = &median->parent; + struct casereader *sorted_reader = casewriter_make_reader (i->writer); + i->writer = NULL; + + order_stats_accumulate (&os, 1, + sorted_reader, + i->weight, + i->subject, + i->exclude); + i->dbl[0] = percentile_calculate (median, PC_HAVERAGE); + statistic_destroy (&median->parent.parent); + } + v->f = i->dbl[0]; } break; case SD: @@ -1006,9 +1024,9 @@ dump_aggregate_info (struct agr_proc *agr, struct casewriter *output) case MAX | FSTRING: case MIN | FSTRING: if (i->int1) - memcpy (v->s, i->string, var_get_width (i->dest)); + memcpy (value_str_rw (v, width), i->string, width); else - memset (v->s, ' ', var_get_width (i->dest)); + value_set_missing (v, width); break; case FGT: case FGT | FSTRING: @@ -1032,7 +1050,7 @@ dump_aggregate_info (struct agr_proc *agr, struct casewriter *output) break; case N: case N | FSTRING: - v->f = i->dbl[0]; + v->f = i->dbl[0]; break; case NU: case NU | FSTRING: @@ -1045,15 +1063,9 @@ dump_aggregate_info (struct agr_proc *agr, struct casewriter *output) case FIRST | FSTRING: case LAST | FSTRING: if (i->int1) - memcpy (v->s, i->string, var_get_width (i->dest)); + memcpy (value_str_rw (v, width), i->string, width); else - memset (v->s, ' ', var_get_width (i->dest)); - break; - case N_NO_VARS: - v->f = i->dbl[0]; - break; - case NU_NO_VARS: - v->f = i->int1; + value_set_missing (v, width); break; case NMISS: case NMISS | FSTRING: @@ -1069,18 +1081,15 @@ dump_aggregate_info (struct agr_proc *agr, struct casewriter *output) } } - casewriter_write (output, &c); + casewriter_write (output, c); } /* Resets the state for all the aggregate functions. */ static void -initialize_aggregate_info (struct agr_proc *agr, const struct ccase *input) +initialize_aggregate_info (struct agr_proc *agr) { 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->saw_missing = false; @@ -1102,17 +1111,24 @@ initialize_aggregate_info (struct agr_proc *agr, const struct ccase *input) break; case MEDIAN: { - struct case_ordering *ordering = case_ordering_create (); + struct caseproto *proto; + struct subcase ordering; + + proto = caseproto_create (); + proto = caseproto_add_width (proto, 0); + proto = caseproto_add_width (proto, 0); if ( ! iter->subject) - iter->subject = var_create_internal (0); + iter->subject = dict_create_internal_var (0, 0); if ( ! iter->weight) - iter->weight = var_create_internal (1); + iter->weight = dict_create_internal_var (1, 0); - case_ordering_add_var (ordering, iter->subject, SRT_ASCEND); + subcase_init_var (&ordering, iter->subject, SC_ASCEND); + iter->writer = sort_create_writer (&ordering, proto); + subcase_destroy (&ordering); + caseproto_unref (proto); - iter->writer = sort_create_writer (ordering, 2); iter->cc = 0; } break;