1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 #include <data/any-writer.h>
25 #include <data/case-sink.h>
26 #include <data/case.h>
27 #include <data/casefile.h>
28 #include <data/dictionary.h>
29 #include <data/file-handle-def.h>
30 #include <data/procedure.h>
31 #include <data/settings.h>
32 #include <data/storage-stream.h>
33 #include <data/sys-file-writer.h>
34 #include <data/variable.h>
35 #include <language/command.h>
36 #include <language/data-io/file-handle.h>
37 #include <language/lexer/lexer.h>
38 #include <language/lexer/variable-parser.h>
39 #include <language/stats/sort-criteria.h>
40 #include <libpspp/alloc.h>
41 #include <libpspp/assertion.h>
42 #include <libpspp/message.h>
43 #include <libpspp/misc.h>
44 #include <libpspp/pool.h>
45 #include <libpspp/str.h>
46 #include <math/moments.h>
47 #include <math/sort.h>
50 #define _(msgid) gettext (msgid)
52 /* Argument for AGGREGATE function. */
55 double f; /* Numeric. */
56 char *c; /* Short or long string. */
59 /* Specifies how to make an aggregate variable. */
62 struct agr_var *next; /* Next in list. */
64 /* Collected during parsing. */
65 struct variable *src; /* Source variable. */
66 struct variable *dest; /* Target variable. */
67 int function; /* Function. */
68 int include_missing; /* 1=Include user-missing values. */
69 union agr_argument arg[2]; /* Arguments. */
71 /* Accumulated during AGGREGATE execution. */
76 struct moments1 *moments;
79 /* Aggregation functions. */
82 NONE, SUM, MEAN, SD, MAX, MIN, PGT, PLT, PIN, POUT, FGT, FLT, FIN,
83 FOUT, N, NU, NMISS, NUMISS, FIRST, LAST,
84 N_AGR_FUNCS, N_NO_VARS, NU_NO_VARS,
85 FUNC = 0x1f, /* Function mask. */
86 FSTRING = 1<<5, /* String function bit. */
89 /* Attributes of an aggregation function. */
92 const char *name; /* Aggregation function name. */
93 size_t n_args; /* Number of arguments. */
94 int alpha_type; /* When given ALPHA arguments, output type. */
95 struct fmt_spec format; /* Format spec if alpha_type != ALPHA. */
98 /* Attributes of aggregation functions. */
99 static const struct agr_func agr_func_tab[] =
101 {"<NONE>", 0, -1, {0, 0, 0}},
102 {"SUM", 0, -1, {FMT_F, 8, 2}},
103 {"MEAN", 0, -1, {FMT_F, 8, 2}},
104 {"SD", 0, -1, {FMT_F, 8, 2}},
105 {"MAX", 0, ALPHA, {-1, -1, -1}},
106 {"MIN", 0, ALPHA, {-1, -1, -1}},
107 {"PGT", 1, NUMERIC, {FMT_F, 5, 1}},
108 {"PLT", 1, NUMERIC, {FMT_F, 5, 1}},
109 {"PIN", 2, NUMERIC, {FMT_F, 5, 1}},
110 {"POUT", 2, NUMERIC, {FMT_F, 5, 1}},
111 {"FGT", 1, NUMERIC, {FMT_F, 5, 3}},
112 {"FLT", 1, NUMERIC, {FMT_F, 5, 3}},
113 {"FIN", 2, NUMERIC, {FMT_F, 5, 3}},
114 {"FOUT", 2, NUMERIC, {FMT_F, 5, 3}},
115 {"N", 0, NUMERIC, {FMT_F, 7, 0}},
116 {"NU", 0, NUMERIC, {FMT_F, 7, 0}},
117 {"NMISS", 0, NUMERIC, {FMT_F, 7, 0}},
118 {"NUMISS", 0, NUMERIC, {FMT_F, 7, 0}},
119 {"FIRST", 0, ALPHA, {-1, -1, -1}},
120 {"LAST", 0, ALPHA, {-1, -1, -1}},
121 {NULL, 0, -1, {-1, -1, -1}},
122 {"N", 0, NUMERIC, {FMT_F, 7, 0}},
123 {"NU", 0, NUMERIC, {FMT_F, 7, 0}},
126 /* Missing value types. */
127 enum missing_treatment
129 ITEMWISE, /* Missing values item by item. */
130 COLUMNWISE /* Missing values column by column. */
133 /* An entire AGGREGATE procedure. */
136 /* We have either an output file or a sink. */
137 struct any_writer *writer; /* Output file, or null if none. */
138 struct case_sink *sink; /* Sink, or null if none. */
140 /* Break variables. */
141 struct sort_criteria *sort; /* Sort criteria. */
142 struct variable **break_vars; /* Break variables. */
143 size_t break_var_cnt; /* Number of break variables. */
144 struct ccase break_case; /* Last values of break variables. */
146 enum missing_treatment missing; /* How to treat missing values. */
147 struct agr_var *agr_vars; /* First aggregate variable. */
148 struct dictionary *dict; /* Aggregate dictionary. */
149 const struct dictionary *src_dict; /* Dict of the source */
150 int case_cnt; /* Counts aggregated cases. */
151 struct ccase agr_case; /* Aggregate case for output. */
154 static void initialize_aggregate_info (struct agr_proc *,
155 const struct ccase *);
158 static bool parse_aggregate_functions (struct lexer *, const struct dictionary *,
160 static void agr_destroy (struct agr_proc *);
161 static bool aggregate_single_case (struct agr_proc *agr,
162 const struct ccase *input,
163 struct ccase *output);
164 static void dump_aggregate_info (struct agr_proc *agr, struct ccase *output);
166 /* Aggregating to the active file. */
167 static bool agr_to_active_file (const struct ccase *, void *aux, const struct dataset *);
169 /* Aggregating to a system file. */
170 static bool presorted_agr_to_sysfile (const struct ccase *, void *aux, const struct dataset *);
174 /* Parses and executes the AGGREGATE procedure. */
176 cmd_aggregate (struct lexer *lexer, struct dataset *ds)
178 struct dictionary *dict = dataset_dict (ds);
180 struct file_handle *out_file = NULL;
182 bool copy_documents = false;
183 bool presorted = false;
186 memset(&agr, 0 , sizeof (agr));
187 agr.missing = ITEMWISE;
188 case_nullify (&agr.break_case);
190 agr.dict = dict_create ();
192 dict_set_label (agr.dict, dict_get_label (dict));
193 dict_set_documents (agr.dict, dict_get_documents (dict));
195 /* OUTFILE subcommand must be first. */
196 if (!lex_force_match_id (lexer, "OUTFILE"))
198 lex_match (lexer, '=');
199 if (!lex_match (lexer, '*'))
201 out_file = fh_parse (lexer, FH_REF_FILE | FH_REF_SCRATCH);
202 if (out_file == NULL)
206 /* Read most of the subcommands. */
209 lex_match (lexer, '/');
211 if (lex_match_id (lexer, "MISSING"))
213 lex_match (lexer, '=');
214 if (!lex_match_id (lexer, "COLUMNWISE"))
216 lex_error (lexer, _("while expecting COLUMNWISE"));
219 agr.missing = COLUMNWISE;
221 else if (lex_match_id (lexer, "DOCUMENT"))
222 copy_documents = true;
223 else if (lex_match_id (lexer, "PRESORTED"))
225 else if (lex_match_id (lexer, "BREAK"))
229 lex_match (lexer, '=');
230 agr.sort = sort_parse_criteria (lexer, dict,
231 &agr.break_vars, &agr.break_var_cnt,
232 &saw_direction, NULL);
233 if (agr.sort == NULL)
236 for (i = 0; i < agr.break_var_cnt; i++)
237 dict_clone_var_assert (agr.dict, agr.break_vars[i],
238 agr.break_vars[i]->name);
240 /* BREAK must follow the options. */
245 lex_error (lexer, _("expecting BREAK"));
249 if (presorted && saw_direction)
250 msg (SW, _("When PRESORTED is specified, specifying sorting directions "
251 "with (A) or (D) has no effect. Output data will be sorted "
252 "the same way as the input data."));
254 /* Read in the aggregate functions. */
255 lex_match (lexer, '/');
256 if (!parse_aggregate_functions (lexer, dict, &agr))
259 /* Delete documents. */
261 dict_set_documents (agr.dict, NULL);
263 /* Cancel SPLIT FILE. */
264 dict_set_split_vars (agr.dict, NULL, 0);
268 case_create (&agr.agr_case, dict_get_next_value_idx (agr.dict));
270 /* Output to active file or external file? */
271 if (out_file == NULL)
273 /* The active file will be replaced by the aggregated data,
274 so TEMPORARY is moot. */
275 proc_cancel_temporary_transformations (ds);
277 if (agr.sort != NULL && !presorted)
279 if (!sort_active_file_in_place (ds, agr.sort))
283 agr.sink = create_case_sink (&storage_sink_class, agr.dict, NULL);
284 if (agr.sink->class->open != NULL)
285 agr.sink->class->open (agr.sink);
287 create_case_sink (&null_sink_class,
289 if (!procedure (ds, agr_to_active_file, &agr))
291 if (agr.case_cnt > 0)
293 dump_aggregate_info (&agr, &agr.agr_case);
294 if (!agr.sink->class->write (agr.sink, &agr.agr_case))
297 discard_variables (ds);
299 dataset_set_dict (ds, agr.dict);
302 agr.sink->class->make_source (agr.sink));
303 free_case_sink (agr.sink);
307 agr.writer = any_writer_open (out_file, agr.dict);
308 if (agr.writer == NULL)
311 if (agr.sort != NULL && !presorted)
313 /* Sorting is needed. */
314 struct casefile *dst;
315 struct casereader *reader;
319 dst = sort_active_file_to_casefile (ds, agr.sort);
322 reader = casefile_get_destructive_reader (dst);
323 while (ok && casereader_read_xfer (reader, &c))
325 if (aggregate_single_case (&agr, &c, &agr.agr_case))
326 ok = any_writer_write (agr.writer, &agr.agr_case);
329 casereader_destroy (reader);
331 ok = !casefile_error (dst);
332 casefile_destroy (dst);
338 /* Active file is already sorted. */
339 if (!procedure (ds, presorted_agr_to_sysfile, &agr))
343 if (agr.case_cnt > 0)
345 dump_aggregate_info (&agr, &agr.agr_case);
346 any_writer_write (agr.writer, &agr.agr_case);
348 if (any_writer_error (agr.writer))
357 return CMD_CASCADING_FAILURE;
360 /* Parse all the aggregate functions. */
362 parse_aggregate_functions (struct lexer *lexer, const struct dictionary *dict, struct agr_proc *agr)
364 struct agr_var *tail; /* Tail of linked list starting at agr->vars. */
366 /* Parse everything. */
373 struct string function_name;
376 const struct agr_func *function;
379 union agr_argument arg[2];
381 struct variable **src;
395 /* Parse the list of target variables. */
396 while (!lex_match (lexer, '='))
398 size_t n_dest_prev = n_dest;
400 if (!parse_DATA_LIST_vars (lexer, &dest, &n_dest,
401 PV_APPEND | PV_SINGLE | PV_NO_SCRATCH))
404 /* Assign empty labels. */
408 dest_label = xnrealloc (dest_label, n_dest, sizeof *dest_label);
409 for (j = n_dest_prev; j < n_dest; j++)
410 dest_label[j] = NULL;
415 if (lex_token (lexer) == T_STRING)
418 ds_init_string (&label, lex_tokstr (lexer));
420 ds_truncate (&label, 255);
421 dest_label[n_dest - 1] = ds_xstrdup (&label);
427 /* Get the name of the aggregation function. */
428 if (lex_token (lexer) != T_ID)
430 lex_error (lexer, _("expecting aggregation function"));
436 ds_init_string (&function_name, lex_tokstr (lexer));
438 ds_chomp (&function_name, '.');
440 if (lex_tokid(lexer)[strlen (lex_tokid (lexer)) - 1] == '.')
443 for (function = agr_func_tab; function->name; function++)
444 if (!strcasecmp (function->name, ds_cstr (&function_name)))
446 if (NULL == function->name)
448 msg (SE, _("Unknown aggregation function %s."),
449 ds_cstr (&function_name));
452 ds_destroy (&function_name);
453 func_index = function - agr_func_tab;
456 /* Check for leading lparen. */
457 if (!lex_match (lexer, '('))
460 func_index = N_NO_VARS;
461 else if (func_index == NU)
462 func_index = NU_NO_VARS;
465 lex_error (lexer, _("expecting `('"));
471 /* Parse list of source variables. */
473 int pv_opts = PV_NO_SCRATCH;
475 if (func_index == SUM || func_index == MEAN || func_index == SD)
476 pv_opts |= PV_NUMERIC;
477 else if (function->n_args)
478 pv_opts |= PV_SAME_TYPE;
480 if (!parse_variables (lexer, dict, &src, &n_src, pv_opts))
484 /* Parse function arguments, for those functions that
485 require arguments. */
486 if (function->n_args != 0)
487 for (i = 0; i < function->n_args; i++)
491 lex_match (lexer, ',');
492 if (lex_token (lexer) == T_STRING)
494 arg[i].c = ds_xstrdup (lex_tokstr (lexer));
497 else if (lex_is_number (lexer))
499 arg[i].f = lex_tokval (lexer);
502 msg (SE, _("Missing argument %d to %s."), i + 1,
509 if (type != src[0]->type)
511 msg (SE, _("Arguments to %s must be of same type as "
512 "source variables."),
518 /* Trailing rparen. */
519 if (!lex_match (lexer, ')'))
521 lex_error (lexer, _("expecting `)'"));
525 /* Now check that the number of source variables match
526 the number of target variables. If we check earlier
527 than this, the user can get very misleading error
528 message, i.e. `AGGREGATE x=SUM(y t).' will get this
529 error message when a proper message would be more
530 like `unknown variable t'. */
533 msg (SE, _("Number of source variables (%u) does not match "
534 "number of target variables (%u)."),
535 (unsigned) n_src, (unsigned) n_dest);
539 if ((func_index == PIN || func_index == POUT
540 || func_index == FIN || func_index == FOUT)
541 && ((src[0]->type == NUMERIC && arg[0].f > arg[1].f)
542 || (src[0]->type == ALPHA
543 && str_compare_rpad (arg[0].c, arg[1].c) > 0)))
545 union agr_argument t = arg[0];
549 msg (SW, _("The value arguments passed to the %s function "
550 "are out-of-order. They will be treated as if "
551 "they had been specified in the correct order."),
556 /* Finally add these to the linked list of aggregation
558 for (i = 0; i < n_dest; i++)
560 struct agr_var *v = xmalloc (sizeof *v);
562 /* Add variable to chain. */
563 if (agr->agr_vars != NULL)
571 /* Create the target variable in the aggregate
574 struct variable *destvar;
576 v->function = func_index;
582 if (src[i]->type == ALPHA)
584 v->function |= FSTRING;
585 v->string = xmalloc (src[i]->width);
588 if (function->alpha_type == ALPHA)
589 destvar = dict_clone_var (agr->dict, v->src, dest[i]);
592 assert (v->src->type == NUMERIC
593 || function->alpha_type == NUMERIC);
594 destvar = dict_create_var (agr->dict, dest[i], 0);
598 if ((func_index == N || func_index == NMISS)
599 && dict_get_weight (dict) != NULL)
600 f = fmt_for_output (FMT_F, 8, 2);
602 f = function->format;
603 destvar->print = destvar->write = f;
609 destvar = dict_create_var (agr->dict, dest[i], 0);
610 if (func_index == N_NO_VARS && dict_get_weight (dict) != NULL)
611 f = fmt_for_output (FMT_F, 8, 2);
613 f = function->format;
614 destvar->print = destvar->write = f;
619 msg (SE, _("Variable name %s is not unique within the "
620 "aggregate file dictionary, which contains "
621 "the aggregate variables and the break "
630 destvar->label = dest_label[i];
631 dest_label[i] = NULL;
637 v->include_missing = include_missing;
643 if (v->src->type == NUMERIC)
644 for (j = 0; j < function->n_args; j++)
645 v->arg[j].f = arg[j].f;
647 for (j = 0; j < function->n_args; j++)
648 v->arg[j].c = xstrdup (arg[j].c);
652 if (src != NULL && src[0]->type == ALPHA)
653 for (i = 0; i < function->n_args; i++)
663 if (!lex_match (lexer, '/'))
665 if (lex_token (lexer) == '.')
668 lex_error (lexer, "expecting end of command");
674 ds_destroy (&function_name);
675 for (i = 0; i < n_dest; i++)
678 free (dest_label[i]);
684 if (src && n_src && src[0]->type == ALPHA)
685 for (i = 0; i < function->n_args; i++)
698 agr_destroy (struct agr_proc *agr)
700 struct agr_var *iter, *next;
702 any_writer_close (agr->writer);
703 if (agr->sort != NULL)
704 sort_destroy_criteria (agr->sort);
705 free (agr->break_vars);
706 case_destroy (&agr->break_case);
707 for (iter = agr->agr_vars; iter; iter = next)
711 if (iter->function & FSTRING)
716 n_args = agr_func_tab[iter->function & FUNC].n_args;
717 for (i = 0; i < n_args; i++)
718 free (iter->arg[i].c);
721 else if (iter->function == SD)
722 moments1_destroy (iter->moments);
725 if (agr->dict != NULL)
726 dict_destroy (agr->dict);
728 case_destroy (&agr->agr_case);
733 static void accumulate_aggregate_info (struct agr_proc *,
734 const struct ccase *);
735 static void dump_aggregate_info (struct agr_proc *, struct ccase *);
737 /* Processes a single case INPUT for aggregation. If output is
738 warranted, writes it to OUTPUT and returns true.
739 Otherwise, returns false and OUTPUT is unmodified. */
741 aggregate_single_case (struct agr_proc *agr,
742 const struct ccase *input, struct ccase *output)
744 bool finished_group = false;
746 if (agr->case_cnt++ == 0)
747 initialize_aggregate_info (agr, input);
748 else if (case_compare (&agr->break_case, input,
749 agr->break_vars, agr->break_var_cnt))
751 dump_aggregate_info (agr, output);
752 finished_group = true;
754 initialize_aggregate_info (agr, input);
757 accumulate_aggregate_info (agr, input);
758 return finished_group;
761 /* Accumulates aggregation data from the case INPUT. */
763 accumulate_aggregate_info (struct agr_proc *agr,
764 const struct ccase *input)
766 struct agr_var *iter;
768 bool bad_warn = true;
770 weight = dict_get_case_weight (agr->src_dict, input, &bad_warn);
772 for (iter = agr->agr_vars; iter; iter = iter->next)
775 const union value *v = case_data (input, iter->src->fv);
777 if ((!iter->include_missing
778 && mv_is_value_missing (&iter->src->miss, v))
779 || (iter->include_missing && iter->src->type == NUMERIC
782 switch (iter->function)
785 case NMISS | FSTRING:
786 iter->dbl[0] += weight;
789 case NUMISS | FSTRING:
797 /* This is horrible. There are too many possibilities. */
798 switch (iter->function)
801 iter->dbl[0] += v->f * weight;
805 iter->dbl[0] += v->f * weight;
806 iter->dbl[1] += weight;
809 moments1_add (iter->moments, v->f, weight);
812 iter->dbl[0] = max (iter->dbl[0], v->f);
816 if (memcmp (iter->string, v->s, iter->src->width) < 0)
817 memcpy (iter->string, v->s, iter->src->width);
821 iter->dbl[0] = min (iter->dbl[0], v->f);
825 if (memcmp (iter->string, v->s, iter->src->width) > 0)
826 memcpy (iter->string, v->s, iter->src->width);
831 if (v->f > iter->arg[0].f)
832 iter->dbl[0] += weight;
833 iter->dbl[1] += weight;
837 if (memcmp (iter->arg[0].c, v->s, iter->src->width) < 0)
838 iter->dbl[0] += weight;
839 iter->dbl[1] += weight;
843 if (v->f < iter->arg[0].f)
844 iter->dbl[0] += weight;
845 iter->dbl[1] += weight;
849 if (memcmp (iter->arg[0].c, v->s, iter->src->width) > 0)
850 iter->dbl[0] += weight;
851 iter->dbl[1] += weight;
855 if (iter->arg[0].f <= v->f && v->f <= iter->arg[1].f)
856 iter->dbl[0] += weight;
857 iter->dbl[1] += weight;
861 if (memcmp (iter->arg[0].c, v->s, iter->src->width) <= 0
862 && memcmp (iter->arg[1].c, v->s, iter->src->width) >= 0)
863 iter->dbl[0] += weight;
864 iter->dbl[1] += weight;
868 if (iter->arg[0].f > v->f || v->f > iter->arg[1].f)
869 iter->dbl[0] += weight;
870 iter->dbl[1] += weight;
874 if (memcmp (iter->arg[0].c, v->s, iter->src->width) > 0
875 || memcmp (iter->arg[1].c, v->s, iter->src->width) < 0)
876 iter->dbl[0] += weight;
877 iter->dbl[1] += weight;
881 iter->dbl[0] += weight;
894 case FIRST | FSTRING:
897 memcpy (iter->string, v->s, iter->src->width);
906 memcpy (iter->string, v->s, iter->src->width);
910 case NMISS | FSTRING:
912 case NUMISS | FSTRING:
913 /* Our value is not missing or it would have been
914 caught earlier. Nothing to do. */
920 switch (iter->function)
923 iter->dbl[0] += weight;
934 /* We've come to a record that differs from the previous in one or
935 more of the break variables. Make an output record from the
936 accumulated statistics in the OUTPUT case. */
938 dump_aggregate_info (struct agr_proc *agr, struct ccase *output)
944 for (i = 0; i < agr->break_var_cnt; i++)
946 struct variable *v = agr->break_vars[i];
947 memcpy (case_data_rw (output, value_idx),
948 case_data (&agr->break_case, v->fv),
949 sizeof (union value) * v->nv);
957 for (i = agr->agr_vars; i; i = i->next)
959 union value *v = case_data_rw (output, i->dest->fv);
961 if (agr->missing == COLUMNWISE && i->missing != 0
962 && (i->function & FUNC) != N && (i->function & FUNC) != NU
963 && (i->function & FUNC) != NMISS && (i->function & FUNC) != NUMISS)
965 if (i->dest->type == ALPHA)
966 memset (v->s, ' ', i->dest->width);
975 v->f = i->int1 ? i->dbl[0] : SYSMIS;
978 v->f = i->dbl[1] != 0.0 ? i->dbl[0] / i->dbl[1] : SYSMIS;
984 /* FIXME: we should use two passes. */
985 moments1_calculate (i->moments, NULL, NULL, &variance,
987 if (variance != SYSMIS)
988 v->f = sqrt (variance);
995 v->f = i->int1 ? i->dbl[0] : SYSMIS;
1000 memcpy (v->s, i->string, i->dest->width);
1002 memset (v->s, ' ', i->dest->width);
1011 case FOUT | FSTRING:
1012 v->f = i->dbl[1] ? i->dbl[0] / i->dbl[1] : SYSMIS;
1021 case POUT | FSTRING:
1022 v->f = i->dbl[1] ? i->dbl[0] / i->dbl[1] * 100.0 : SYSMIS;
1034 v->f = i->int1 ? i->dbl[0] : SYSMIS;
1036 case FIRST | FSTRING:
1037 case LAST | FSTRING:
1039 memcpy (v->s, i->string, i->dest->width);
1041 memset (v->s, ' ', i->dest->width);
1050 case NMISS | FSTRING:
1054 case NUMISS | FSTRING:
1064 /* Resets the state for all the aggregate functions. */
1066 initialize_aggregate_info (struct agr_proc *agr, const struct ccase *input)
1068 struct agr_var *iter;
1070 case_destroy (&agr->break_case);
1071 case_clone (&agr->break_case, input);
1073 for (iter = agr->agr_vars; iter; iter = iter->next)
1076 iter->dbl[0] = iter->dbl[1] = iter->dbl[2] = 0.0;
1077 iter->int1 = iter->int2 = 0;
1078 switch (iter->function)
1081 iter->dbl[0] = DBL_MAX;
1084 memset (iter->string, 255, iter->src->width);
1087 iter->dbl[0] = -DBL_MAX;
1090 memset (iter->string, 0, iter->src->width);
1093 if (iter->moments == NULL)
1094 iter->moments = moments1_create (MOMENT_VARIANCE);
1096 moments1_clear (iter->moments);
1104 /* Aggregate each case as it comes through. Cases which aren't needed
1106 Returns true if successful, false if an I/O error occurred. */
1108 agr_to_active_file (const struct ccase *c, void *agr_, const struct dataset *ds UNUSED)
1110 struct agr_proc *agr = agr_;
1112 if (aggregate_single_case (agr, c, &agr->agr_case))
1113 return agr->sink->class->write (agr->sink, &agr->agr_case);
1118 /* Aggregate the current case and output it if we passed a
1121 presorted_agr_to_sysfile (const struct ccase *c, void *agr_,
1122 const struct dataset *ds UNUSED)
1124 struct agr_proc *agr = agr_;
1126 if (aggregate_single_case (agr, c, &agr->agr_case))
1127 return any_writer_write (agr->writer, &agr->agr_case);