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
26 #include "file-handle.h"
38 #include "debug-print.h"
40 /* Specifies how to make an aggregate variable. */
43 struct agr_var *next; /* Next in list. */
45 /* Collected during parsing. */
46 struct variable *src; /* Source variable. */
47 struct variable *dest; /* Target variable. */
48 int function; /* Function. */
49 int include_missing; /* 1=Include user-missing values. */
50 union value arg[2]; /* Arguments. */
52 /* Accumulated during AGGREGATE execution. */
59 /* Aggregation functions. */
62 NONE, SUM, MEAN, SD, MAX, MIN, PGT, PLT, PIN, POUT, FGT, FLT, FIN,
63 FOUT, N, NU, NMISS, NUMISS, FIRST, LAST,
64 N_AGR_FUNCS, N_NO_VARS, NU_NO_VARS,
65 FUNC = 0x1f, /* Function mask. */
66 FSTRING = 1<<5, /* String function bit. */
69 /* Attributes of an aggregation function. */
72 const char *name; /* Aggregation function name. */
73 int n_args; /* Number of arguments. */
74 int alpha_type; /* When given ALPHA arguments, output type. */
75 struct fmt_spec format; /* Format spec if alpha_type != ALPHA. */
78 /* Attributes of aggregation functions. */
79 static struct agr_func agr_func_tab[] =
81 {"<NONE>", 0, -1, {0, 0, 0}},
82 {"SUM", 0, -1, {FMT_F, 8, 2}},
83 {"MEAN", 0, -1, {FMT_F, 8, 2}},
84 {"SD", 0, -1, {FMT_F, 8, 2}},
85 {"MAX", 0, ALPHA, {-1, -1, -1}},
86 {"MIN", 0, ALPHA, {-1, -1, -1}},
87 {"PGT", 1, NUMERIC, {FMT_F, 5, 1}},
88 {"PLT", 1, NUMERIC, {FMT_F, 5, 1}},
89 {"PIN", 2, NUMERIC, {FMT_F, 5, 1}},
90 {"POUT", 2, NUMERIC, {FMT_F, 5, 1}},
91 {"FGT", 1, NUMERIC, {FMT_F, 5, 3}},
92 {"FLT", 1, NUMERIC, {FMT_F, 5, 3}},
93 {"FIN", 2, NUMERIC, {FMT_F, 5, 3}},
94 {"FOUT", 2, NUMERIC, {FMT_F, 5, 3}},
95 {"N", 0, NUMERIC, {FMT_F, 7, 0}},
96 {"NU", 0, NUMERIC, {FMT_F, 7, 0}},
97 {"NMISS", 0, NUMERIC, {FMT_F, 7, 0}},
98 {"NUMISS", 0, NUMERIC, {FMT_F, 7, 0}},
99 {"FIRST", 0, ALPHA, {-1, -1, -1}},
100 {"LAST", 0, ALPHA, {-1, -1, -1}},
101 {NULL, 0, -1, {-1, -1, -1}},
102 {"N", 0, NUMERIC, {FMT_F, 7, 0}},
103 {"NU", 0, NUMERIC, {FMT_F, 7, 0}},
106 /* Output file, or NULL for the active file. */
107 static struct file_handle *outfile;
109 /* Missing value types. */
112 ITEMWISE, /* Missing values item by item. */
113 COLUMNWISE /* Missing values column by column. */
116 /* ITEMWISE or COLUMNWISE. */
119 /* Aggregate variables. */
120 static struct agr_var *agr_first, *agr_next;
122 /* Aggregate dictionary. */
123 static struct dictionary *agr_dict;
125 /* Number of cases passed through aggregation. */
126 static int case_count;
128 /* Last values of the break variables. */
129 static union value *prev_case;
131 /* Buffers for use by the 10x transformation. */
132 static flt64 *buf64_1xx;
133 static struct ccase *buf_1xx;
135 static void initialize_aggregate_info (void);
138 static int parse_aggregate_functions (void);
139 static void free_aggregate_functions (void);
140 static int aggregate_single_case (struct ccase *input, struct ccase *output);
141 static int create_sysfile (void);
143 static int agr_00x_trns_proc (struct trns_header *, struct ccase *);
144 static void agr_00x_end_func (void *);
145 static int agr_10x_trns_proc (struct trns_header *, struct ccase *);
146 static void agr_10x_trns_free (struct trns_header *);
147 static void agr_10x_end_func (void *);
148 static int agr_11x_func (write_case_data);
151 static void debug_print (int flags);
156 /* Parses and executes the AGGREGATE procedure. */
161 int parse_sort_variables (void);
163 /* Have we seen these subcommands? */
171 agr_dict = dict_create ();
172 dict_set_label (agr_dict, dict_get_label (default_dict));
173 dict_set_documents (agr_dict, dict_get_documents (default_dict));
175 lex_match_id ("AGGREGATE");
177 /* Read most of the subcommands. */
182 if (lex_match_id ("OUTFILE"))
187 dict_destroy (agr_dict);
188 msg (SE, _("%s subcommand given multiple times."),"OUTFILE");
198 outfile = fh_parse_file_handle ();
202 dict_destroy (agr_dict);
207 else if (lex_match_id ("MISSING"))
210 if (!lex_match_id ("COLUMNWISE"))
213 dict_destroy (agr_dict);
214 lex_error (_("while expecting COLUMNWISE"));
217 missing = COLUMNWISE;
219 else if (lex_match_id ("DOCUMENT"))
221 else if (lex_match_id ("PRESORTED"))
223 else if (lex_match_id ("BREAK"))
228 dict_destroy (agr_dict);
229 msg (SE, _("%s subcommand given multiple times."),"BREAK");
235 if (!parse_sort_variables ())
237 dict_destroy (agr_dict);
244 for (i = 0; i < nv_sort; i++)
248 v = dict_clone_var (agr_dict, v_sort[i], v_sort[i]->name);
256 /* Check for proper syntax. */
258 msg (SW, _("BREAK subcommand not specified."));
260 /* Read in the aggregate functions. */
261 if (!parse_aggregate_functions ())
263 free_aggregate_functions ();
268 /* Delete documents. */
270 dict_set_documents (agr_dict, NULL);
272 /* Cancel SPLIT FILE. */
273 dict_set_split_vars (agr_dict, NULL, 0);
281 initialize_aggregate_info ();
283 /* How to implement all this... There are three important variables:
284 whether output is going to the active file (0) or a separate file
285 (1); whether the input data is presorted (0) or needs sorting
286 (1); whether there is a temporary transformation (1) or not (0).
287 The eight cases are as follows:
289 000 (0): Pass it through an aggregate transformation that
292 001 (1): Cancel the temporary transformation and handle as 000.
294 010 (2): Set up a SORT CASES and aggregate the output, writing
295 the results to the active file.
297 011 (3): Cancel the temporary transformation and handle as 010.
299 100 (4): Pass it through an aggregate transformation that doesn't
300 modify the data but merely writes it to the output file.
302 101 (5): Handled as 100.
304 110 (6): Set up a SORT CASES and capture the output, aggregate
305 it, write it to the output file without modifying the active
308 111 (7): Handled as 110. */
315 if (nv_sort != 0 && (seen & 4) == 0)
335 struct trns_header *t = xmalloc (sizeof *t);
336 t->proc = agr_00x_trns_proc;
338 add_transformation (t);
341 temp_dict = agr_dict;
346 procedure (NULL, NULL, agr_00x_end_func, NULL);
353 if (!create_sysfile ())
357 struct trns_header *t = xmalloc (sizeof *t);
358 t->proc = agr_10x_trns_proc;
359 t->free = agr_10x_trns_free;
360 add_transformation (t);
362 procedure (NULL, NULL, agr_10x_end_func, NULL);
372 if (!create_sysfile ())
374 read_sort_output (agr_11x_func, NULL);
377 struct ccase *save_temp_case = temp_case;
380 temp_case = save_temp_case;
395 free_aggregate_functions ();
403 free_aggregate_functions ();
409 /* Create a system file for use in aggregation to an external file,
410 and allocate temporary buffers for writing out cases. */
412 create_sysfile (void)
414 struct sfm_write_info w;
417 w.compress = set_scompression;
418 if (!sfm_write_dictionary (&w))
420 free_aggregate_functions ();
422 dict_destroy (agr_dict);
426 buf64_1xx = xmalloc (sizeof *buf64_1xx * w.case_size);
427 buf_1xx = xmalloc (sizeof (struct ccase)
428 + (sizeof (union value)
429 * (dict_get_value_cnt (agr_dict) - 1)));
434 /* Parse all the aggregate functions. */
436 parse_aggregate_functions (void)
438 agr_first = agr_next = NULL;
440 /* Parse everything. */
448 struct agr_func *function;
453 struct variable **src;
466 /* Parse the list of target variables. */
467 while (!lex_match ('='))
469 int n_dest_prev = n_dest;
471 if (!parse_DATA_LIST_vars (&dest, &n_dest, PV_APPEND | PV_SINGLE | PV_NO_SCRATCH))
474 /* Assign empty labels. */
478 dest_label = xrealloc (dest_label, sizeof *dest_label * n_dest);
479 for (j = n_dest_prev; j < n_dest; j++)
480 dest_label[j] = NULL;
483 if (token == T_STRING)
485 ds_truncate (&tokstr, 120);
486 dest_label[n_dest - 1] = xstrdup (ds_value (&tokstr));
491 /* Get the name of the aggregation function. */
494 lex_error (_("expecting aggregation function"));
499 if (tokid[strlen (tokid) - 1] == '.')
502 tokid[strlen (tokid) - 1] = 0;
505 for (function = agr_func_tab; function->name; function++)
506 if (!strcmp (function->name, tokid))
508 if (NULL == function->name)
510 msg (SE, _("Unknown aggregation function %s."), tokid);
513 func_index = function - agr_func_tab;
516 /* Check for leading lparen. */
517 if (!lex_match ('('))
520 func_index = N_NO_VARS;
521 else if (func_index == NU)
522 func_index = NU_NO_VARS;
525 lex_error (_("expecting `('"));
529 /* Parse list of source variables. */
531 int pv_opts = PV_NO_SCRATCH;
533 if (func_index == SUM || func_index == MEAN || func_index == SD)
534 pv_opts |= PV_NUMERIC;
535 else if (function->n_args)
536 pv_opts |= PV_SAME_TYPE;
538 if (!parse_variables (default_dict, &src, &n_src, pv_opts))
542 /* Parse function arguments, for those functions that
543 require arguments. */
544 if (function->n_args != 0)
545 for (i = 0; i < function->n_args; i++)
550 if (token == T_STRING)
552 arg[i].c = xstrdup (ds_value (&tokstr));
555 else if (token == T_NUM)
560 msg (SE, _("Missing argument %d to %s."), i + 1, function->name);
566 if (type != src[0]->type)
568 msg (SE, _("Arguments to %s must be of same type as "
569 "source variables."),
575 /* Trailing rparen. */
578 lex_error (_("expecting `)'"));
582 /* Now check that the number of source variables match the
583 number of target variables. Do this here because if we
584 do it earlier then the user can get very misleading error
585 messages; i.e., `AGGREGATE x=SUM(y t).' will get this
586 error message when a proper message would be more like
587 `unknown variable t'. */
590 msg (SE, _("Number of source variables (%d) does not match "
591 "number of target variables (%d)."),
597 /* Finally add these to the linked list of aggregation
599 for (i = 0; i < n_dest; i++)
601 struct agr_var *v = xmalloc (sizeof *v);
603 /* Add variable to chain. */
605 agr_next = agr_next->next = v;
607 agr_first = agr_next = v;
608 agr_next->next = NULL;
610 /* Create the target variable in the aggregate
613 struct variable *destvar;
615 agr_next->function = func_index;
621 agr_next->src = src[i];
623 if (src[i]->type == ALPHA)
625 agr_next->function |= FSTRING;
626 agr_next->string = xmalloc (src[i]->width);
629 if (agr_next->src->type == NUMERIC || function->alpha_type == NUMERIC)
632 output_width = agr_next->src->width;
634 if (function->alpha_type == ALPHA)
635 destvar = dict_clone_var (agr_dict, agr_next->src, dest[i]);
638 destvar = dict_create_var (agr_dict, dest[i], output_width);
639 if (output_width == 0)
640 destvar->print = destvar->write = function->format;
641 if (output_width == 0 && dict_get_weight (default_dict) != NULL
642 && (func_index == N || func_index == N_NO_VARS
643 || func_index == NU || func_index == NU_NO_VARS))
645 struct fmt_spec f = {FMT_F, 8, 2};
647 destvar->print = destvar->write = f;
651 agr_next->src = NULL;
652 destvar = dict_create_var (agr_dict, dest[i], 0);
657 msg (SE, _("Variable name %s is not unique within the "
658 "aggregate file dictionary, which contains "
659 "the aggregate variables and the break "
670 destvar->label = dest_label[i];
671 dest_label[i] = NULL;
673 else if (function->alpha_type == ALPHA)
674 destvar->print = destvar->write = function->format;
676 agr_next->dest = destvar;
679 agr_next->include_missing = include_missing;
681 if (agr_next->src != NULL)
685 if (agr_next->src->type == NUMERIC)
686 for (j = 0; j < function->n_args; j++)
687 agr_next->arg[j].f = arg[j].f;
689 for (j = 0; j < function->n_args; j++)
690 agr_next->arg[j].c = xstrdup (arg[j].c);
694 if (src != NULL && src[0]->type == ALPHA)
695 for (i = 0; i < function->n_args; i++)
705 if (!lex_match ('/'))
710 lex_error ("expecting end of command");
716 for (i = 0; i < n_dest; i++)
719 free (dest_label[i]);
725 if (src && n_src && src[0]->type == ALPHA)
726 for (i = 0; i < function->n_args; i++)
737 /* Frees all the state for the AGGREGATE procedure. */
739 free_aggregate_functions (void)
741 struct agr_var *iter, *next;
744 dict_destroy (agr_dict);
745 for (iter = agr_first; iter; iter = next)
749 if (iter->function & FSTRING)
754 n_args = agr_func_tab[iter->function & FUNC].n_args;
755 for (i = 0; i < n_args; i++)
756 free (iter->arg[i].c);
765 static void accumulate_aggregate_info (struct ccase *input);
766 static void dump_aggregate_info (struct ccase *output);
768 /* Processes a single case INPUT for aggregation. If output is
769 warranted, it is written to case OUTPUT, which may be (but need not
770 be) an alias to INPUT. Returns -1 when output is performed, -2
772 /* The code in this function has an eerie similarity to
773 vfm.c:SPLIT_FILE_procfunc()... */
775 aggregate_single_case (struct ccase *input, struct ccase *output)
777 /* The first case always begins a new break group. We also need to
778 preserve the values of the case for later comparison. */
779 if (case_count++ == 0)
786 for (i = 0; i < nv_sort; i++)
787 n_elem += v_sort[i]->nv;
790 prev_case = xmalloc (sizeof *prev_case * n_elem);
792 /* Copy INPUT into prev_case. */
794 union value *iter = prev_case;
797 for (i = 0; i < nv_sort; i++)
799 struct variable *v = v_sort[i];
801 if (v->type == NUMERIC)
802 (iter++)->f = input->data[v->fv].f;
805 memcpy (iter->s, input->data[v->fv].s, v->width);
811 accumulate_aggregate_info (input);
816 /* Compare the value of each break variable to the values on the
819 union value *iter = prev_case;
822 for (i = 0; i < nv_sort; i++)
824 struct variable *v = v_sort[i];
829 if (input->data[v->fv].f != iter->f)
834 if (memcmp (input->data[v->fv].s, iter->s, v->width))
844 accumulate_aggregate_info (input);
849 /* The values of the break variable are different from the values on
850 the previous case. That means that it's time to dump aggregate
852 dump_aggregate_info (output);
853 initialize_aggregate_info ();
854 accumulate_aggregate_info (input);
856 /* Copy INPUT into prev_case. */
858 union value *iter = prev_case;
861 for (i = 0; i < nv_sort; i++)
863 struct variable *v = v_sort[i];
865 if (v->type == NUMERIC)
866 (iter++)->f = input->data[v->fv].f;
869 memcpy (iter->s, input->data[v->fv].s, v->width);
878 /* Accumulates aggregation data from the case INPUT. */
880 accumulate_aggregate_info (struct ccase *input)
882 struct agr_var *iter;
885 weight = dict_get_case_weight (default_dict, input);
887 for (iter = agr_first; iter; iter = iter->next)
890 union value *v = &input->data[iter->src->fv];
892 if ((!iter->include_missing && is_missing (v, iter->src))
893 || (iter->include_missing && iter->src->type == NUMERIC
896 switch (iter->function)
899 iter->dbl[0] += weight;
909 /* This is horrible. There are too many possibilities. */
910 switch (iter->function)
913 iter->dbl[0] += v->f;
916 iter->dbl[0] += v->f * weight;
917 iter->dbl[1] += weight;
921 double product = v->f * weight;
922 iter->dbl[0] += product;
923 iter->dbl[1] += product * v->f;
924 iter->dbl[2] += weight;
928 iter->dbl[0] = max (iter->dbl[0], v->f);
932 if (memcmp (iter->string, v->s, iter->src->width) < 0)
933 memcpy (iter->string, v->s, iter->src->width);
937 iter->dbl[0] = min (iter->dbl[0], v->f);
941 if (memcmp (iter->string, v->s, iter->src->width) > 0)
942 memcpy (iter->string, v->s, iter->src->width);
947 if (v->f > iter->arg[0].f)
948 iter->dbl[0] += weight;
949 iter->dbl[1] += weight;
953 if (memcmp (iter->arg[0].c, v->s, iter->src->width) < 0)
954 iter->dbl[0] += weight;
955 iter->dbl[1] += weight;
959 if (v->f < iter->arg[0].f)
960 iter->dbl[0] += weight;
961 iter->dbl[1] += weight;
965 if (memcmp (iter->arg[0].c, v->s, iter->src->width) > 0)
966 iter->dbl[0] += weight;
967 iter->dbl[1] += weight;
971 if (iter->arg[0].f <= v->f && v->f <= iter->arg[1].f)
972 iter->dbl[0] += weight;
973 iter->dbl[1] += weight;
977 if (memcmp (iter->arg[0].c, v->s, iter->src->width) <= 0
978 && memcmp (iter->arg[1].c, v->s, iter->src->width) >= 0)
979 iter->dbl[0] += weight;
980 iter->dbl[1] += weight;
984 if (iter->arg[0].f > v->f || v->f > iter->arg[1].f)
985 iter->dbl[0] += weight;
986 iter->dbl[1] += weight;
990 if (memcmp (iter->arg[0].c, v->s, iter->src->width) > 0
991 && memcmp (iter->arg[1].c, v->s, iter->src->width) < 0)
992 iter->dbl[0] += weight;
993 iter->dbl[1] += weight;
996 iter->dbl[0] += weight;
1002 if (iter->int1 == 0)
1004 iter->dbl[0] = v->f;
1008 case FIRST | FSTRING:
1009 if (iter->int1 == 0)
1011 memcpy (iter->string, v->s, iter->src->width);
1016 iter->dbl[0] = v->f;
1019 case LAST | FSTRING:
1020 memcpy (iter->string, v->s, iter->src->width);
1027 switch (iter->function)
1030 iter->dbl[0] += weight;
1041 /* We've come to a record that differs from the previous in one or
1042 more of the break variables. Make an output record from the
1043 accumulated statistics in the OUTPUT case. */
1045 dump_aggregate_info (struct ccase *output)
1047 debug_printf (("(dumping "));
1055 for (i = 0; i < nv_sort; i++)
1056 n_elem += v_sort[i]->nv;
1058 debug_printf (("n_elem=%d:", n_elem));
1059 memcpy (output->data, prev_case, sizeof (union value) * n_elem);
1065 for (i = agr_first; i; i = i->next)
1067 union value *v = &output->data[i->dest->fv];
1069 debug_printf ((" %d,%d", i->dest->fv, i->dest->nv));
1071 if (missing == COLUMNWISE && i->missing != 0
1072 && (i->function & FUNC) != N && (i->function & FUNC) != NU
1073 && (i->function & FUNC) != NMISS && (i->function & FUNC) != NUMISS)
1075 if (i->function & FSTRING)
1076 memset (v->s, ' ', i->dest->width);
1082 switch (i->function)
1088 v->f = i->dbl[1] != 0.0 ? i->dbl[0] / i->dbl[1] : SYSMIS;
1091 v->f = ((i->dbl[2] > 1.0)
1092 ? calc_stddev (calc_variance (i->dbl, i->dbl[2]))
1097 v->f = i->int1 ? i->dbl[0] : SYSMIS;
1102 memcpy (v->s, i->string, i->dest->width);
1104 memset (v->s, ' ', i->dest->width);
1109 case FOUT | FSTRING:
1110 v->f = i->int2 ? (double) i->int1 / (double) i->int2 : SYSMIS;
1116 v->f = i->dbl[1] ? i->dbl[0] / i->dbl[1] : SYSMIS;
1125 case POUT | FSTRING:
1126 v->f = i->dbl[1] ? i->dbl[0] / i->dbl[1] * 100.0 : SYSMIS;
1136 v->f = i->int1 ? i->dbl[0] : SYSMIS;
1138 case FIRST | FSTRING:
1139 case LAST | FSTRING:
1141 memcpy (v->s, i->string, i->dest->width);
1143 memset (v->s, ' ', i->dest->width);
1162 debug_printf ((") "));
1165 /* Resets the state for all the aggregate functions. */
1167 initialize_aggregate_info (void)
1169 struct agr_var *iter;
1171 for (iter = agr_first; iter; iter = iter->next)
1174 switch (iter->function)
1177 iter->dbl[0] = DBL_MAX;
1180 memset (iter->string, 255, iter->src->width);
1183 iter->dbl[0] = -DBL_MAX;
1186 memset (iter->string, 0, iter->src->width);
1189 iter->dbl[0] = iter->dbl[1] = iter->dbl[2] = 0.0;
1190 iter->int1 = iter->int2 = 0;
1196 /* Aggregate each case as it comes through. Cases which aren't needed
1199 agr_00x_trns_proc (struct trns_header *h UNUSED, struct ccase *c)
1201 int code = aggregate_single_case (c, compaction_case);
1202 debug_printf (("%d ", code));
1206 /* Output the last aggregate case. It's okay to call the vfm_sink's
1207 write() method here because end_func is called so soon after all
1208 the cases have been output; very little has been cleaned up at this
1211 agr_00x_end_func (void *aux UNUSED)
1213 /* Ensure that info for the last break group gets written to the
1215 dump_aggregate_info (compaction_case);
1216 vfm_sink_info.ncases++;
1220 /* Transform the aggregate case buf_1xx, in internal format, to system
1221 file format, in buf64_1xx, and write the resultant case to the
1224 write_case_to_sfm (void)
1226 flt64 *p = buf64_1xx;
1229 for (i = 0; i < dict_get_var_cnt (agr_dict); i++)
1231 struct variable *v = dict_get_var (agr_dict, i);
1233 if (v->type == NUMERIC)
1235 double src = buf_1xx->data[v->fv].f;
1243 memcpy (p, buf_1xx->data[v->fv].s, v->width);
1244 memset (&((char *) p)[v->width], ' ',
1245 REM_RND_UP (v->width, sizeof (flt64)));
1246 p += DIV_RND_UP (v->width, sizeof (flt64));
1250 sfm_write_case (outfile, buf64_1xx, p - buf64_1xx);
1253 /* Aggregate the current case and output it if we passed a
1256 agr_10x_trns_proc (struct trns_header *h UNUSED, struct ccase *c)
1258 int code = aggregate_single_case (c, buf_1xx);
1260 assert (code == -2 || code == -1);
1262 write_case_to_sfm ();
1266 /* Close the system file now that we're done with it. */
1268 agr_10x_trns_free (struct trns_header *h UNUSED)
1270 fh_close_handle (outfile);
1273 /* Ensure that info for the last break group gets written to the
1276 agr_10x_end_func (void *aux UNUSED)
1278 dump_aggregate_info (buf_1xx);
1279 write_case_to_sfm ();
1282 /* When called with temp_case non-NULL (the normal case), runs the
1283 case through the aggregater and outputs it to the system file if
1284 appropriate. If temp_case is NULL, finishes up writing the last
1285 case if necessary. */
1287 agr_11x_func (write_case_data wc_data UNUSED)
1289 if (temp_case != NULL)
1291 int code = aggregate_single_case (temp_case, buf_1xx);
1293 assert (code == -2 || code == -1);
1295 write_case_to_sfm ();
1301 dump_aggregate_info (buf_1xx);
1302 write_case_to_sfm ();
1304 fh_close_handle (outfile);
1311 /* Print out useful debugging information. */
1313 debug_print (int flags)
1315 printf ("AGGREGATE\n /OUTFILE=%s\n",
1316 outfile ? fh_handle_filename (outfile) : "*");
1318 if (missing == COLUMNWISE)
1319 puts (" /MISSING=COLUMNWISE");
1322 puts (" /DOCUMENT");
1324 puts (" /PRESORTED");
1329 printf (" /BREAK=");
1330 for (i = 0; i < nv_sort; i++)
1331 printf ("%s(%c) ", v_sort[i]->name,
1332 v_sort[i]->p.srt.order == SRT_ASCEND ? 'A' : 'D');
1333 putc ('\n', stdout);
1337 struct agr_var *iter;
1339 for (iter = agr_first; iter; iter = iter->next)
1341 struct agr_func *f = &agr_func_tab[iter->function & FUNC];
1343 printf (" /%s", iter->dest->name);
1344 if (iter->dest->label)
1345 printf ("'%s'", iter->dest->label);
1346 printf ("=%s(%s", f->name, iter->src->name);
1351 for (i = 0; i < f->n_args; i++)
1354 if (iter->src->type == NUMERIC)
1355 printf ("%g", iter->arg[i].f);
1357 printf ("%.*s", iter->src->width, iter->arg[i].c);
1365 #endif /* DEBUGGING */