1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000 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., 59 Temple Place - Suite 330, Boston, MA
27 #include "file-handle.h"
40 /*#define DEBUGGING 1*/
41 #include "debug-print.h"
43 /* Specifies how to make an aggregate variable. */
46 struct agr_var *next; /* Next in list. */
48 /* Collected during parsing. */
49 struct variable *src; /* Source variable. */
50 struct variable *dest; /* Target variable. */
51 int function; /* Function. */
52 int include_missing; /* 1=Include user-missing values. */
53 union value arg[2]; /* Arguments. */
55 /* Accumulated during AGGREGATE execution. */
62 /* Aggregation functions. */
65 NONE, SUM, MEAN, SD, MAX, MIN, PGT, PLT, PIN, POUT, FGT, FLT, FIN,
66 FOUT, N, NU, NMISS, NUMISS, FIRST, LAST,
67 N_AGR_FUNCS, N_NO_VARS, NU_NO_VARS,
68 FUNC = 0x1f, /* Function mask. */
69 FSTRING = 1<<5, /* String function bit. */
70 FWEIGHT = 1<<6, /* Weighted function bit. */
71 FOPTIONS = FSTRING | FWEIGHT /* Function options mask. */
74 /* Attributes of an aggregation function. */
77 const char *name; /* Aggregation function name. */
78 int n_args; /* Number of arguments. */
79 int alpha_type; /* When given ALPHA arguments, output type. */
80 struct fmt_spec format; /* Format spec if alpha_type != ALPHA. */
83 /* Attributes of aggregation functions. */
84 static struct agr_func agr_func_tab[] =
86 {"<NONE>", 0, -1, {0, 0, 0}},
87 {"SUM", 0, -1, {FMT_F, 8, 2}},
88 {"MEAN", 0, -1, {FMT_F, 8, 2}},
89 {"SD", 0, -1, {FMT_F, 8, 2}},
90 {"MAX", 0, ALPHA, {-1, -1, -1}},
91 {"MIN", 0, ALPHA, {-1, -1, -1}},
92 {"PGT", 1, NUMERIC, {FMT_F, 5, 1}},
93 {"PLT", 1, NUMERIC, {FMT_F, 5, 1}},
94 {"PIN", 2, NUMERIC, {FMT_F, 5, 1}},
95 {"POUT", 2, NUMERIC, {FMT_F, 5, 1}},
96 {"FGT", 1, NUMERIC, {FMT_F, 5, 3}},
97 {"FLT", 1, NUMERIC, {FMT_F, 5, 3}},
98 {"FIN", 2, NUMERIC, {FMT_F, 5, 3}},
99 {"FOUT", 2, NUMERIC, {FMT_F, 5, 3}},
100 {"N", 0, NUMERIC, {FMT_F, 7, 0}},
101 {"NU", 0, NUMERIC, {FMT_F, 7, 0}},
102 {"NMISS", 0, NUMERIC, {FMT_F, 7, 0}},
103 {"NUMISS", 0, NUMERIC, {FMT_F, 7, 0}},
104 {"FIRST", 0, ALPHA, {-1, -1, -1}},
105 {"LAST", 0, ALPHA, {-1, -1, -1}},
106 {NULL, 0, -1, {-1, -1, -1}},
107 {"N", 0, NUMERIC, {FMT_F, 7, 0}},
108 {"NU", 0, NUMERIC, {FMT_F, 7, 0}},
111 /* Output file, or NULL for the active file. */
112 static struct file_handle *outfile;
114 /* Missing value types. */
117 ITEMWISE, /* Missing values item by item. */
118 COLUMNWISE /* Missing values column by column. */
121 /* ITEMWISE or COLUMNWISE. */
124 /* Aggregate variables. */
125 static struct agr_var *agr_first, *agr_next;
127 /* Aggregate dictionary. */
128 static struct dictionary *agr_dict;
130 /* Number of cases passed through aggregation. */
131 static int case_count;
133 /* Last values of the break variables. */
134 static union value *prev_case;
136 /* Buffers for use by the 10x transformation. */
137 static flt64 *buf64_1xx;
138 static struct ccase *buf_1xx;
140 static void initialize_aggregate_info (void);
143 static int parse_aggregate_functions (void);
144 static void free_aggregate_functions (void);
145 static int aggregate_single_case (struct ccase *input, struct ccase *output);
146 static int create_sysfile (void);
148 static int agr_00x_trns_proc (struct trns_header *, struct ccase *);
149 static void agr_00x_end_func (void);
150 static int agr_10x_trns_proc (struct trns_header *, struct ccase *);
151 static void agr_10x_trns_free (struct trns_header *);
152 static void agr_10x_end_func (void);
153 static int agr_11x_func (void);
156 static void debug_print (int flags);
161 /* Parses and executes the AGGREGATE procedure. */
166 int parse_sort_variables (void);
168 /* Have we seen these subcommands? */
176 agr_dict = new_dictionary (1);
178 lex_match_id ("AGGREGATE");
180 /* Read most of the subcommands. */
185 if (lex_match_id ("OUTFILE"))
190 free_dictionary (agr_dict);
191 msg (SE, _("OUTFILE specified multiple times."));
201 outfile = fh_parse_file_handle ();
205 free_dictionary (agr_dict);
210 else if (lex_match_id ("MISSING"))
213 if (!lex_match_id ("COLUMNWISE"))
216 free_dictionary (agr_dict);
217 lex_error (_("while expecting COLUMNWISE"));
220 missing = COLUMNWISE;
222 else if (lex_match_id ("DOCUMENT"))
224 else if (lex_match_id ("PRESORTED"))
226 else if (lex_match_id ("BREAK"))
231 free_dictionary (agr_dict);
232 msg (SE, _("BREAK specified multiple times."));
238 if (!parse_sort_variables ())
240 free_dictionary (agr_dict);
247 for (i = 0; i < nv_sort; i++)
251 v = dup_variable (agr_dict, v_sort[i], v_sort[i]->name);
259 /* Check for proper syntax. */
261 msg (SW, _("BREAK subcommand not specified."));
263 /* Read in the aggregate functions. */
264 if (!parse_aggregate_functions ())
266 free_aggregate_functions ();
271 /* Delete documents. */
274 free (agr_dict->documents);
275 agr_dict->documents = NULL;
276 agr_dict->n_documents = 0;
279 /* Cancel SPLIT FILE. */
280 default_dict.n_splits = 0;
281 free (default_dict.splits);
282 default_dict.splits = NULL;
290 initialize_aggregate_info ();
292 /* How to implement all this... There are three important variables:
293 whether output is going to the active file (0) or a separate file
294 (1); whether the input data is presorted (0) or needs sorting
295 (1); whether there is a temporary transformation (1) or not (0).
296 The eight cases are as follows:
298 000 (0): Pass it through an aggregate transformation that
301 001 (1): Cancel the temporary transformation and handle as 000.
303 010 (2): Set up a SORT CASES and aggregate the output, writing
304 the results to the active file.
306 011 (3): Cancel the temporary transformation and handle as 010.
308 100 (4): Pass it through an aggregate transformation that doesn't
309 modify the data but merely writes it to the output file.
311 101 (5): Handled as 100.
313 110 (6): Set up a SORT CASES and capture the output, aggregate
314 it, write it to the output file without modifying the active
317 111 (7): Handled as 110. */
324 if (nv_sort != 0 && (seen & 4) == 0)
344 struct trns_header *t = xmalloc (sizeof *t);
345 t->proc = agr_00x_trns_proc;
347 add_transformation (t);
350 temp_dict = agr_dict;
355 procedure (NULL, NULL, agr_00x_end_func);
362 if (!create_sysfile ())
366 struct trns_header *t = xmalloc (sizeof *t);
367 t->proc = agr_10x_trns_proc;
368 t->free = agr_10x_trns_free;
369 add_transformation (t);
371 procedure (NULL, NULL, agr_10x_end_func);
381 if (!create_sysfile ())
383 read_sort_output (agr_11x_func);
386 struct ccase *save_temp_case = temp_case;
389 temp_case = save_temp_case;
404 free_aggregate_functions ();
412 free_aggregate_functions ();
418 /* Create a system file for use in aggregation to an external file,
419 and allocate temporary buffers for writing out cases. */
421 create_sysfile (void)
423 struct sfm_write_info w;
426 w.compress = set_scompression;
427 if (!sfm_write_dictionary (&w))
429 free_aggregate_functions ();
431 free_dictionary (agr_dict);
435 buf64_1xx = xmalloc (sizeof *buf64_1xx * w.case_size);
436 buf_1xx = xmalloc (sizeof (struct ccase) + sizeof (union value) * (agr_dict->nval - 1));
441 /* Parse all the aggregate functions. */
443 parse_aggregate_functions (void)
445 agr_first = agr_next = NULL;
447 /* Anticipate weighting for optimization later. */
448 update_weighting (&default_dict);
450 /* Parse everything. */
458 struct agr_func *function;
463 struct variable **src;
476 /* Parse the list of target variables. */
477 while (!lex_match ('='))
479 int n_dest_prev = n_dest;
481 if (!parse_DATA_LIST_vars (&dest, &n_dest, PV_APPEND | PV_SINGLE | PV_NO_SCRATCH))
484 /* Assign empty labels. */
488 dest_label = xrealloc (dest_label, sizeof *dest_label * n_dest);
489 for (j = n_dest_prev; j < n_dest; j++)
490 dest_label[j] = NULL;
493 if (token == T_STRING)
495 ds_truncate (&tokstr, 120);
496 dest_label[n_dest - 1] = xstrdup (ds_value (&tokstr));
501 /* Get the name of the aggregation function. */
504 lex_error (_("expecting aggregation function"));
509 if (tokid[strlen (tokid) - 1] == '.')
512 tokid[strlen (tokid) - 1] = 0;
515 for (function = agr_func_tab; function->name; function++)
516 if (!strcmp (function->name, tokid))
518 if (NULL == function->name)
520 msg (SE, _("Unknown aggregation function %s."), tokid);
523 func_index = function - agr_func_tab;
526 /* Check for leading lparen. */
527 if (!lex_match ('('))
530 func_index = N_NO_VARS;
531 else if (func_index == NU)
532 func_index = NU_NO_VARS;
535 lex_error (_("expecting `('"));
539 /* Parse list of source variables. */
541 int pv_opts = PV_NO_SCRATCH;
543 if (func_index == SUM || func_index == MEAN || func_index == SD)
544 pv_opts |= PV_NUMERIC;
545 else if (function->n_args)
546 pv_opts |= PV_SAME_TYPE;
548 if (!parse_variables (&default_dict, &src, &n_src, pv_opts))
552 /* Parse function arguments, for those functions that
553 require arguments. */
554 if (function->n_args != 0)
555 for (i = 0; i < function->n_args; i++)
560 if (token == T_STRING)
562 arg[i].c = xstrdup (ds_value (&tokstr));
565 else if (token == T_NUM)
570 msg (SE, _("Missing argument %d to %s."), i + 1, function->name);
576 if (type != src[0]->type)
578 msg (SE, _("Arguments to %s must be of same type as "
579 "source variables."),
585 /* Trailing rparen. */
588 lex_error (_("expecting `)'"));
592 /* Now check that the number of source variables match the
593 number of target variables. Do this here because if we
594 do it earlier then the user can get very misleading error
595 messages; i.e., `AGGREGATE x=SUM(y t).' will get this
596 error message when a proper message would be more like
597 `unknown variable t'. */
600 msg (SE, _("Number of source variables (%d) does not match "
601 "number of target variables (%d)."),
607 /* Finally add these to the linked list of aggregation
609 for (i = 0; i < n_dest; i++)
611 struct agr_var *v = xmalloc (sizeof *v);
613 /* Add variable to chain. */
615 agr_next = agr_next->next = v;
617 agr_first = agr_next = v;
618 agr_next->next = NULL;
620 /* Create the target variable in the aggregate
623 struct variable *destvar;
625 agr_next->function = func_index;
631 agr_next->src = src[i];
633 if (src[i]->type == ALPHA)
635 agr_next->function |= FSTRING;
636 agr_next->string = xmalloc (src[i]->width);
639 if (default_dict.weight_index != -1)
640 agr_next->function |= FWEIGHT;
642 if (agr_next->src->type == NUMERIC)
643 output_type = NUMERIC;
645 output_type = function->alpha_type;
647 if (function->alpha_type == ALPHA)
648 destvar = dup_variable (agr_dict, agr_next->src, dest[i]);
651 destvar = create_variable (agr_dict, dest[i], output_type,
652 agr_next->src->width);
653 if (output_type == NUMERIC)
654 destvar->print = destvar->write = function->format;
655 if (output_type == NUMERIC && default_dict.weight_index != -1
656 && (func_index == N || func_index == N_NO_VARS
657 || func_index == NU || func_index == NU_NO_VARS))
659 struct fmt_spec f = {FMT_F, 8, 2};
661 destvar->print = destvar->write = f;
665 agr_next->src = NULL;
666 destvar = create_variable (agr_dict, dest[i], NUMERIC, 0);
671 msg (SE, _("Variable name %s is not unique within the "
672 "aggregate file dictionary, which contains "
673 "the aggregate variables and the break "
683 destvar->label = dest_label[i];
684 dest_label[i] = NULL;
686 else if (function->alpha_type == ALPHA)
687 destvar->print = destvar->write = function->format;
689 agr_next->dest = destvar;
692 agr_next->include_missing = include_missing;
694 if (agr_next->src != NULL)
698 if (agr_next->src->type == NUMERIC)
699 for (j = 0; j < function->n_args; j++)
700 agr_next->arg[j].f = arg[j].f;
702 for (j = 0; j < function->n_args; j++)
703 agr_next->arg[j].c = xstrdup (arg[j].c);
707 if (src != NULL && src[0]->type == ALPHA)
708 for (i = 0; i < function->n_args; i++)
718 if (!lex_match ('/'))
723 lex_error ("expecting end of command");
729 for (i = 0; i < n_dest; i++)
732 free (dest_label[i]);
738 if (src && n_src && src[0]->type == ALPHA)
739 for (i = 0; i < function->n_args; i++)
750 /* Frees all the state for the AGGREGATE procedure. */
752 free_aggregate_functions (void)
754 struct agr_var *iter, *next;
757 free_dictionary (agr_dict);
758 for (iter = agr_first; iter; iter = next)
762 if (iter->function & FSTRING)
767 n_args = agr_func_tab[iter->function & FUNC].n_args;
768 for (i = 0; i < n_args; i++)
769 free (iter->arg[i].c);
778 static void accumulate_aggregate_info (struct ccase *input);
779 static void dump_aggregate_info (struct ccase *output);
781 /* Processes a single case INPUT for aggregation. If output is
782 warranted, it is written to case OUTPUT, which may be (but need not
783 be) an alias to INPUT. Returns -1 when output is performed, -2
785 /* The code in this function has an eerie similarity to
786 vfm.c:SPLIT_FILE_procfunc()... */
788 aggregate_single_case (struct ccase *input, struct ccase *output)
790 /* The first case always begins a new break group. We also need to
791 preserve the values of the case for later comparison. */
792 if (case_count++ == 0)
799 for (i = 0; i < nv_sort; i++)
800 n_elem += v_sort[i]->nv;
803 prev_case = xmalloc (sizeof *prev_case * n_elem);
805 /* Copy INPUT into prev_case. */
807 union value *iter = prev_case;
810 for (i = 0; i < nv_sort; i++)
812 struct variable *v = v_sort[i];
814 if (v->type == NUMERIC)
815 (iter++)->f = input->data[v->fv].f;
818 memcpy (iter->s, input->data[v->fv].s, v->width);
824 accumulate_aggregate_info (input);
829 /* Compare the value of each break variable to the values on the
832 union value *iter = prev_case;
835 for (i = 0; i < nv_sort; i++)
837 struct variable *v = v_sort[i];
842 if (approx_ne (input->data[v->fv].f, iter->f))
847 if (memcmp (input->data[v->fv].s, iter->s, v->width))
857 accumulate_aggregate_info (input);
862 /* The values of the break variable are different from the values on
863 the previous case. That means that it's time to dump aggregate
865 dump_aggregate_info (output);
866 initialize_aggregate_info ();
867 accumulate_aggregate_info (input);
869 /* Copy INPUT into prev_case. */
871 union value *iter = prev_case;
874 for (i = 0; i < nv_sort; i++)
876 struct variable *v = v_sort[i];
878 if (v->type == NUMERIC)
879 (iter++)->f = input->data[v->fv].f;
882 memcpy (iter->s, input->data[v->fv].s, v->width);
891 /* Accumulates aggregation data from the case INPUT. */
893 accumulate_aggregate_info (struct ccase *input)
895 struct agr_var *iter;
897 #define WEIGHT (input->data[default_dict.weight_index].f)
899 for (iter = agr_first; iter; iter = iter->next)
902 union value *v = &input->data[iter->src->fv];
904 if ((!iter->include_missing && is_missing (v, iter->src))
905 || (iter->include_missing && iter->src->type == NUMERIC
908 switch (iter->function)
910 case NMISS | FWEIGHT:
911 iter->dbl[0] += WEIGHT;
915 case NUMISS | FWEIGHT:
923 /* This is horrible. There are too many possibilities. */
924 switch (iter->function)
928 iter->dbl[0] += v->f;
931 iter->dbl[0] += v->f;
937 iter->dbl[0] += v->f * w;
942 iter->dbl[0] += v->f;
943 iter->dbl[1] += v->f * v->f;
949 double product = v->f * w;
950 iter->dbl[0] += product;
951 iter->dbl[1] += product * v->f;
957 iter->dbl[0] = max (iter->dbl[0], v->f);
961 case MAX | FSTRING | FWEIGHT:
962 if (memcmp (iter->string, v->s, iter->src->width) < 0)
963 memcpy (iter->string, v->s, iter->src->width);
968 iter->dbl[0] = min (iter->dbl[0], v->f);
972 case MIN | FSTRING | FWEIGHT:
973 if (memcmp (iter->string, v->s, iter->src->width) > 0)
974 memcpy (iter->string, v->s, iter->src->width);
979 if (approx_gt (v->f, iter->arg[0].f))
987 if (approx_gt (v->f, iter->arg[0].f))
994 if (memcmp (iter->arg[0].c, v->s, iter->src->width) < 0)
998 case FGT | FSTRING | FWEIGHT:
999 case PGT | FSTRING | FWEIGHT:
1002 if (memcmp (iter->arg[0].c, v->s, iter->src->width) < 0)
1009 if (approx_lt (v->f, iter->arg[0].f))
1017 if (approx_lt (v->f, iter->arg[0].f))
1024 if (memcmp (iter->arg[0].c, v->s, iter->src->width) > 0)
1028 case FLT | FSTRING | FWEIGHT:
1029 case PLT | FSTRING | FWEIGHT:
1032 if (memcmp (iter->arg[0].c, v->s, iter->src->width) > 0)
1039 if (approx_in_range (v->f, iter->arg[0].f, iter->arg[1].f))
1047 if (approx_in_range (v->f, iter->arg[0].f, iter->arg[1].f))
1054 if (memcmp (iter->arg[0].c, v->s, iter->src->width) <= 0
1055 && memcmp (iter->arg[1].c, v->s, iter->src->width) >= 0)
1059 case FIN | FSTRING | FWEIGHT:
1060 case PIN | FSTRING | FWEIGHT:
1063 if (memcmp (iter->arg[0].c, v->s, iter->src->width) <= 0
1064 && memcmp (iter->arg[1].c, v->s, iter->src->width) >= 0)
1071 if (!approx_in_range (v->f, iter->arg[0].f, iter->arg[1].f))
1075 case FOUT | FWEIGHT:
1076 case POUT | FWEIGHT:
1079 if (!approx_in_range (v->f, iter->arg[0].f, iter->arg[1].f))
1084 case FOUT | FSTRING:
1085 case POUT | FSTRING:
1086 if (memcmp (iter->arg[0].c, v->s, iter->src->width) > 0
1087 && memcmp (iter->arg[1].c, v->s, iter->src->width) < 0)
1091 case FOUT | FSTRING | FWEIGHT:
1092 case POUT | FSTRING | FWEIGHT:
1095 if (memcmp (iter->arg[0].c, v->s, iter->src->width) > 0
1096 && memcmp (iter->arg[1].c, v->s, iter->src->width) < 0)
1102 iter->dbl[0] += WEIGHT;
1110 case FIRST | FWEIGHT:
1111 if (iter->int1 == 0)
1113 iter->dbl[0] = v->f;
1117 case FIRST | FSTRING:
1118 case FIRST | FSTRING | FWEIGHT:
1119 if (iter->int1 == 0)
1121 memcpy (iter->string, v->s, iter->src->width);
1126 case LAST | FWEIGHT:
1127 iter->dbl[0] = v->f;
1130 case LAST | FSTRING:
1131 case LAST | FSTRING | FWEIGHT:
1132 memcpy (iter->string, v->s, iter->src->width);
1139 switch (iter->function)
1141 case N_NO_VARS | FWEIGHT:
1142 iter->dbl[0] += WEIGHT;
1146 case NU_NO_VARS | FWEIGHT:
1155 /* We've come to a record that differs from the previous in one or
1156 more of the break variables. Make an output record from the
1157 accumulated statistics in the OUTPUT case. */
1159 dump_aggregate_info (struct ccase *output)
1161 debug_printf (("(dumping "));
1169 for (i = 0; i < nv_sort; i++)
1170 n_elem += v_sort[i]->nv;
1172 debug_printf (("n_elem=%d:", n_elem));
1173 memcpy (output->data, prev_case, sizeof (union value) * n_elem);
1179 for (i = agr_first; i; i = i->next)
1181 union value *v = &output->data[i->dest->fv];
1183 debug_printf ((" %d,%d", i->dest->fv, i->dest->nv));
1185 if (missing == COLUMNWISE && i->missing != 0
1186 && (i->function & FUNC) != N && (i->function & FUNC) != NU
1187 && (i->function & FUNC) != NMISS && (i->function & FUNC) != NUMISS)
1189 if (i->function & FSTRING)
1190 memset (v->s, ' ', i->dest->width);
1196 switch (i->function)
1203 v->f = i->int1 ? i->dbl[0] / i->int1 : SYSMIS;
1205 case MEAN | FWEIGHT:
1206 v->f = i->dbl[1] != 0.0 ? i->dbl[0] / i->dbl[1] : SYSMIS;
1209 v->f = ((i->int1 > 1)
1210 ? calc_stddev (calc_variance (i->dbl, i->int1))
1214 v->f = ((i->dbl[2] > 1.0)
1215 ? calc_stddev (calc_variance (i->dbl, i->dbl[2]))
1222 v->f = i->int1 ? i->dbl[0] : SYSMIS;
1225 case MAX | FSTRING | FWEIGHT:
1227 case MIN | FSTRING | FWEIGHT:
1229 memcpy (v->s, i->string, i->dest->width);
1231 memset (v->s, ' ', i->dest->width);
1240 case FOUT | FSTRING:
1241 v->f = i->int2 ? (double) i->int1 / (double) i->int2 : SYSMIS;
1244 case FGT | FSTRING | FWEIGHT:
1246 case FLT | FSTRING | FWEIGHT:
1248 case FIN | FSTRING | FWEIGHT:
1249 case FOUT | FWEIGHT:
1250 case FOUT | FSTRING | FWEIGHT:
1251 v->f = i->dbl[1] ? i->dbl[0] / i->dbl[1] : SYSMIS;
1260 case POUT | FSTRING:
1262 ? (double) i->int1 / (double) i->int2 * 100.0
1266 case PGT | FSTRING | FWEIGHT:
1268 case PLT | FSTRING | FWEIGHT:
1270 case PIN | FSTRING | FWEIGHT:
1271 case POUT | FWEIGHT:
1272 case POUT | FSTRING | FWEIGHT:
1273 v->f = i->dbl[1] ? i->dbl[0] / i->dbl[1] * 100.0 : SYSMIS;
1283 case FIRST | FWEIGHT:
1285 case LAST | FWEIGHT:
1286 v->f = i->int1 ? i->dbl[0] : SYSMIS;
1288 case FIRST | FSTRING:
1289 case FIRST | FSTRING | FWEIGHT:
1290 case LAST | FSTRING:
1291 case LAST | FSTRING | FWEIGHT:
1293 memcpy (v->s, i->string, i->dest->width);
1295 memset (v->s, ' ', i->dest->width);
1297 case N_NO_VARS | FWEIGHT:
1302 case NU_NO_VARS | FWEIGHT:
1305 case NMISS | FWEIGHT:
1310 case NUMISS | FWEIGHT:
1318 debug_printf ((") "));
1321 /* Resets the state for all the aggregate functions. */
1323 initialize_aggregate_info (void)
1325 struct agr_var *iter;
1327 for (iter = agr_first; iter; iter = iter->next)
1329 int plain_function = iter->function & ~FWEIGHT;
1332 switch (plain_function)
1335 iter->dbl[0] = DBL_MAX;
1338 memset (iter->string, 255, iter->src->width);
1341 iter->dbl[0] = -DBL_MAX;
1344 memset (iter->string, 0, iter->src->width);
1347 iter->dbl[0] = iter->dbl[1] = iter->dbl[2] = 0.0;
1348 iter->int1 = iter->int2 = 0;
1354 /* Aggregate each case as it comes through. Cases which aren't needed
1357 agr_00x_trns_proc (struct trns_header *h unused, struct ccase *c)
1359 int code = aggregate_single_case (c, compaction_case);
1360 debug_printf (("%d ", code));
1364 /* Output the last aggregate case. It's okay to call the vfm_sink's
1365 write() method here because end_func is called so soon after all
1366 the cases have been output; very little has been cleaned up at this
1369 agr_00x_end_func (void)
1371 /* Ensure that info for the last break group gets written to the
1373 dump_aggregate_info (compaction_case);
1374 vfm_sink_info.ncases++;
1378 /* Transform the aggregate case buf_1xx, in internal format, to system
1379 file format, in buf64_1xx, and write the resultant case to the
1382 write_case_to_sfm (void)
1384 flt64 *p = buf64_1xx;
1387 for (i = 0; i < agr_dict->nvar; i++)
1389 struct variable *v = agr_dict->var[i];
1391 if (v->type == NUMERIC)
1393 double src = buf_1xx->data[v->fv].f;
1401 memcpy (p, buf_1xx->data[v->fv].s, v->width);
1402 memset (&((char *) p)[v->width], ' ',
1403 REM_RND_UP (v->width, sizeof (flt64)));
1404 p += DIV_RND_UP (v->width, sizeof (flt64));
1408 sfm_write_case (outfile, buf64_1xx, p - buf64_1xx);
1411 /* Aggregate the current case and output it if we passed a
1414 agr_10x_trns_proc (struct trns_header *h unused, struct ccase *c)
1416 int code = aggregate_single_case (c, buf_1xx);
1418 assert (code == -2 || code == -1);
1420 write_case_to_sfm ();
1424 /* Close the system file now that we're done with it. */
1426 agr_10x_trns_free (struct trns_header *h unused)
1428 fh_close_handle (outfile);
1431 /* Ensure that info for the last break group gets written to the
1434 agr_10x_end_func (void)
1436 dump_aggregate_info (buf_1xx);
1437 write_case_to_sfm ();
1440 /* When called with temp_case non-NULL (the normal case), runs the
1441 case through the aggregater and outputs it to the system file if
1442 appropriate. If temp_case is NULL, finishes up writing the last
1443 case if necessary. */
1447 if (temp_case != NULL)
1449 int code = aggregate_single_case (temp_case, buf_1xx);
1451 assert (code == -2 || code == -1);
1453 write_case_to_sfm ();
1459 dump_aggregate_info (buf_1xx);
1460 write_case_to_sfm ();
1462 fh_close_handle (outfile);
1469 /* Print out useful debugging information. */
1471 debug_print (int flags)
1473 printf ("AGGREGATE\n /OUTFILE=%s\n",
1474 outfile ? fh_handle_filename (outfile) : "*");
1476 if (missing == COLUMNWISE)
1477 puts (" /MISSING=COLUMNWISE");
1480 puts (" /DOCUMENT");
1482 puts (" /PRESORTED");
1487 printf (" /BREAK=");
1488 for (i = 0; i < nv_sort; i++)
1489 printf ("%s(%c) ", v_sort[i]->name,
1490 v_sort[i]->p.srt.order == SRT_ASCEND ? 'A' : 'D');
1491 putc ('\n', stdout);
1495 struct agr_var *iter;
1497 for (iter = agr_first; iter; iter = iter->next)
1499 struct agr_func *f = &agr_func_tab[iter->function & FUNC];
1501 printf (" /%s", iter->dest->name);
1502 if (iter->dest->label)
1503 printf ("'%s'", iter->dest->label);
1504 printf ("=%s(%s", f->name, iter->src->name);
1509 for (i = 0; i < f->n_args; i++)
1512 if (iter->src->type == NUMERIC)
1513 printf ("%g", iter->arg[i].f);
1515 printf ("%.*s", iter->src->width, iter->arg[i].c);
1523 #endif /* DEBUGGING */