X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Faggregate.c;h=67e8bb91b1c4e27d2006d1e8e7e08646dafb13e9;hb=dcf9b154cbcaa35c3d8459a201b77eec8bcb30bd;hp=6da6242c670a0be3fad5dfaf321f1db73cfd2495;hpb=05e356b2a3087e819ef3b5388e29c822f41502e1;p=pspp-builds.git diff --git a/src/aggregate.c b/src/aggregate.c index 6da6242c..67e8bb91 100644 --- a/src/aggregate.c +++ b/src/aggregate.c @@ -14,13 +14,14 @@ 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 #include "error.h" #include #include "alloc.h" +#include "any-writer.h" #include "case.h" #include "casefile.h" #include "command.h" @@ -33,12 +34,16 @@ #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 { @@ -73,7 +78,7 @@ enum 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. */ }; @@ -117,14 +122,14 @@ enum missing_treatment 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. */ @@ -133,7 +138,8 @@ struct agr_proc 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 *); @@ -164,6 +170,7 @@ cmd_aggregate (void) 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)); @@ -175,7 +182,7 @@ cmd_aggregate (void) 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; } @@ -206,18 +213,13 @@ cmd_aggregate (void) 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; @@ -248,7 +250,6 @@ cmd_aggregate (void) /* 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) @@ -278,7 +279,7 @@ cmd_aggregate (void) } 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; @@ -296,7 +297,7 @@ cmd_aggregate (void) 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); @@ -311,7 +312,7 @@ cmd_aggregate (void) 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); } } @@ -335,7 +336,7 @@ parse_aggregate_functions (struct agr_proc *agr) { char **dest; char **dest_label; - int n_dest; + size_t n_dest; int include_missing; const struct agr_func *function; @@ -344,9 +345,9 @@ parse_aggregate_functions (struct agr_proc *agr) union value arg[2]; struct variable **src; - int n_src; + size_t n_src; - int i; + size_t i; dest = NULL; dest_label = NULL; @@ -360,7 +361,7 @@ parse_aggregate_functions (struct agr_proc *agr) /* 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)) @@ -370,7 +371,7 @@ parse_aggregate_functions (struct agr_proc *agr) { 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; } @@ -454,7 +455,8 @@ parse_aggregate_functions (struct agr_proc *agr) 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; } @@ -484,9 +486,9 @@ parse_aggregate_functions (struct agr_proc *agr) 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; } @@ -494,8 +496,7 @@ parse_aggregate_functions (struct agr_proc *agr) || 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]; @@ -526,7 +527,6 @@ parse_aggregate_functions (struct agr_proc *agr) /* 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; @@ -542,10 +542,11 @@ parse_aggregate_functions (struct agr_proc *agr) } 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) { @@ -651,19 +652,19 @@ agr_destroy (struct agr_proc *agr) { 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++) @@ -693,105 +694,21 @@ static int 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. */ @@ -810,7 +727,8 @@ accumulate_aggregate_info (struct agr_proc *agr, { 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)) { @@ -978,11 +896,11 @@ dump_aggregate_info (struct agr_proc *agr, struct ccase *output) 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; } } @@ -1098,10 +1016,13 @@ dump_aggregate_info (struct agr_proc *agr, struct ccase *output) /* 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; @@ -1154,7 +1075,7 @@ presorted_agr_to_sysfile (struct ccase *c, void *agr_) 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; }