? out.txt
? pspp.list
? rank-1.patch
? rank.patch
? rank.sps
? small2e.aux
? small2e.dvi
? small2e.log
? doc/.dirstamp
? gl/Makefile
? gl/Makefile.am
? gl/Makefile.in
? gl/alloca.c
? gl/alloca.h
? gl/alloca_.h
? gl/asnprintf.c
? gl/asprintf.c
? gl/c-ctype.c
? gl/c-ctype.h
? gl/c-strtod.c
? gl/c-strtod.h
? gl/charset.alias
? gl/config.charset
? gl/doc
? gl/error.c
? gl/error.h
? gl/exit.h
? gl/exitfail.c
? gl/exitfail.h
? gl/full-read.c
? gl/full-read.h
? gl/full-write.c
? gl/full-write.h
? gl/getdelim.c
? gl/getdelim.h
? gl/gethostname.c
? gl/getline.c
? gl/getline.h
? gl/getlogin_r.c
? gl/getlogin_r.h
? gl/getopt.c
? gl/getopt1.c
? gl/getopt_.h
? gl/getopt_int.h
? gl/gettext.h
? gl/intprops.h
? gl/lbrkprop.h
? gl/linebreak.c
? gl/linebreak.h
? gl/localcharset.c
? gl/localcharset.h
? gl/mbchar.c
? gl/mbchar.h
? gl/mbuiter.h
? gl/memcasecmp.c
? gl/memcasecmp.h
? gl/memchr.c
? gl/memcmp.c
? gl/memmem.c
? gl/memmem.h
? gl/memmove.c
? gl/memset.c
? gl/minmax.h
? gl/printf-args.c
? gl/printf-args.h
? gl/printf-parse.c
? gl/printf-parse.h
? gl/progname.c
? gl/progname.h
? gl/readlink.c
? gl/ref-add.sed
? gl/ref-add.sin
? gl/ref-del.sed
? gl/ref-del.sin
? gl/safe-read.c
? gl/safe-read.h
? gl/safe-write.c
? gl/safe-write.h
? gl/size_max.h
? gl/snprintf.c
? gl/snprintf.h
? gl/stat-macros.h
? gl/stdbool_.h
? gl/stdint.h
? gl/stdint_.h
? gl/stpcpy.c
? gl/stpcpy.h
? gl/strcase.h
? gl/strcasecmp.c
? gl/strcspn.c
? gl/strerror.c
? gl/strftime.c
? gl/strftime.h
? gl/strncasecmp.c
? gl/strndup.c
? gl/strndup.h
? gl/strnlen.c
? gl/strnlen.h
? gl/strnlen1.c
? gl/strnlen1.h
? gl/strpbrk.c
? gl/strpbrk.h
? gl/strsep.c
? gl/strsep.h
? gl/strstr.c
? gl/strstr.h
? gl/strtod.c
? gl/strtok_r.c
? gl/strtok_r.h
? gl/strtol.c
? gl/strtoul.c
? gl/time_r.c
? gl/time_r.h
? gl/utf16-ucs4.h
? gl/utf8-ucs4.h
? gl/vasnprintf.c
? gl/vasnprintf.h
? gl/vasprintf.c
? gl/vasprintf.h
? gl/vsnprintf.c
? gl/vsnprintf.h
? gl/wcwidth.h
? gl/xalloc-die.c
? gl/xalloc.h
? gl/xasprintf.c
? gl/xmalloc.c
? gl/xreadlink.c
? gl/xreadlink.h
? gl/xsize.h
? gl/xstrndup.c
? gl/xstrndup.h
? gl/xvasprintf.c
? gl/xvasprintf.h
? gl/m4/absolute-header.m4
? gl/m4/alloca.m4
? gl/m4/assert.m4
? gl/m4/c-strtod.m4
? gl/m4/codeset.m4
? gl/m4/eoverflow.m4
? gl/m4/error.m4
? gl/m4/exitfail.m4
? gl/m4/extensions.m4
? gl/m4/getdelim.m4
? gl/m4/gethostname.m4
? gl/m4/getline.m4
? gl/m4/getlogin_r.m4
? gl/m4/getopt.m4
? gl/m4/gettext.m4
? gl/m4/glibc2.m4
? gl/m4/glibc21.m4
? gl/m4/gnulib-cache.m4
? gl/m4/gnulib-comp.m4
? gl/m4/gnulib-tool.m4
? gl/m4/iconv.m4
? gl/m4/intdiv0.m4
? gl/m4/intmax.m4
? gl/m4/intmax_t.m4
? gl/m4/inttypes-h.m4
? gl/m4/inttypes-pri.m4
? gl/m4/inttypes_h.m4
? gl/m4/lcmessage.m4
? gl/m4/lib-ld.m4
? gl/m4/lib-link.m4
? gl/m4/lib-prefix.m4
? gl/m4/linebreak.m4
? gl/m4/localcharset.m4
? gl/m4/lock.m4
? gl/m4/longdouble.m4
? gl/m4/longlong.m4
? gl/m4/mbchar.m4
? gl/m4/mbiter.m4
? gl/m4/mbrtowc.m4
? gl/m4/mbstate_t.m4
? gl/m4/memcasecmp.m4
? gl/m4/memchr.m4
? gl/m4/memcmp.m4
? gl/m4/memmem.m4
? gl/m4/memmove.m4
? gl/m4/memset.m4
? gl/m4/minmax.m4
? gl/m4/nls.m4
? gl/m4/onceonly_2_57.m4
? gl/m4/po.m4
? gl/m4/printf-posix.m4
? gl/m4/progtest.m4
? gl/m4/readlink.m4
? gl/m4/restrict.m4
? gl/m4/safe-read.m4
? gl/m4/safe-write.m4
? gl/m4/signed.m4
? gl/m4/size_max.m4
? gl/m4/snprintf.m4
? gl/m4/ssize_t.m4
? gl/m4/stat-macros.m4
? gl/m4/stdarg.m4
? gl/m4/stdbool.m4
? gl/m4/stdint.m4
? gl/m4/stdint_h.m4
? gl/m4/stpcpy.m4
? gl/m4/strcase.m4
? gl/m4/strcspn.m4
? gl/m4/strerror.m4
? gl/m4/strerror_r.m4
? gl/m4/strftime.m4
? gl/m4/strndup.m4
? gl/m4/strnlen.m4
? gl/m4/strpbrk.m4
? gl/m4/strsep.m4
? gl/m4/strstr.m4
? gl/m4/strtod.m4
? gl/m4/strtok_r.m4
? gl/m4/strtol.m4
? gl/m4/strtoul.m4
? gl/m4/time_r.m4
? gl/m4/tm_gmtoff.m4
? gl/m4/uintmax_t.m4
? gl/m4/ulonglong.m4
? gl/m4/unistd_h.m4
? gl/m4/utf-ucs4.m4
? gl/m4/vasnprintf.m4
? gl/m4/vasprintf.m4
? gl/m4/visibility.m4
? gl/m4/vsnprintf.m4
? gl/m4/wchar_t.m4
? gl/m4/wcwidth.m4
? gl/m4/wint_t.m4
? gl/m4/xalloc.m4
? gl/m4/xreadlink.m4
? gl/m4/xsize.m4
? gl/m4/xstrndup.m4
? gl/m4/xvasprintf.m4
? intl/ChangeLog
? intl/Makefile
? intl/Makefile.in
? intl/VERSION
? intl/bindtextdom.c
? intl/config.charset
? intl/dcgettext.c
? intl/dcigettext.c
? intl/dcngettext.c
? intl/dgettext.c
? intl/dngettext.c
? intl/eval-plural.h
? intl/explodename.c
? intl/finddomain.c
? intl/gettext.c
? intl/gettextP.h
? intl/gmo.h
? intl/hash-string.h
? intl/intl-compat.c
? intl/l10nflist.c
? intl/langprefs.c
? intl/libgnuintl.h.in
? intl/loadinfo.h
? intl/loadmsgcat.c
? intl/localcharset.c
? intl/localcharset.h
? intl/locale.alias
? intl/localealias.c
? intl/localename.c
? intl/log.c
? intl/ngettext.c
? intl/os2compat.c
? intl/os2compat.h
? intl/osdep.c
? intl/plural-exp.c
? intl/plural-exp.h
? intl/plural.c
? intl/plural.y
? intl/printf-args.c
? intl/printf-args.h
? intl/printf-parse.c
? intl/printf-parse.h
? intl/printf.c
? intl/ref-add.sin
? intl/ref-del.sin
? intl/relocatable.c
? intl/relocatable.h
? intl/textdomain.c
? intl/vasnprintf.c
? intl/vasnprintf.h
? intl/vasnwprintf.h
? intl/wprintf-parse.h
? intl/xsize.h
? lib/gsl-extras/.deps
? lib/gsl-extras/.dirstamp
? lib/gtksheet/.deps
? lib/gtksheet/.dirstamp
? lib/linreg/.deps
? lib/linreg/.dirstamp
? m4/Makefile.am
? m4/codeset.m4
? m4/gettext.m4
? m4/glibc2.m4
? m4/glibc21.m4
? m4/iconv.m4
? m4/intdiv0.m4
? m4/intmax.m4
? m4/inttypes-pri.m4
? m4/inttypes.m4
? m4/inttypes_h.m4
? m4/isc-posix.m4
? m4/lcmessage.m4
? m4/lib-ld.m4
? m4/lib-link.m4
? m4/lib-prefix.m4
? m4/longdouble.m4
? m4/longlong.m4
? m4/nls.m4
? m4/po.m4
? m4/printf-posix.m4
? m4/progtest.m4
? m4/signed.m4
? m4/size_max.m4
? m4/stdint_h.m4
? m4/uintmax_t.m4
? m4/ulonglong.m4
? m4/wchar_t.m4
? m4/wint_t.m4
? m4/xsize.m4
? src/data/.deps
? src/data/.dirstamp
? src/language/.deps
? src/language/.dirstamp
? src/language/control/.deps
? src/language/control/.dirstamp
? src/language/data-io/.deps
? src/language/data-io/.dirstamp
? src/language/data-io/file-handle.c
? src/language/data-io/list.c
? src/language/dictionary/.deps
? src/language/dictionary/.dirstamp
? src/language/expressions/.deps
? src/language/expressions/.dirstamp
? src/language/lexer/.deps
? src/language/lexer/.dirstamp
? src/language/lexer/q2c
? src/language/stats/.deps
? src/language/stats/.dirstamp
? src/language/stats/correlations.c
? src/language/stats/crosstabs.c
? src/language/stats/examine.c
? src/language/stats/frequencies.c
? src/language/stats/means.c
? src/language/stats/oneway.c
? src/language/stats/rank.c
? src/language/stats/regression.c
? src/language/stats/t-test.c
? src/language/tests/.deps
? src/language/tests/.dirstamp
? src/language/utilities/.deps
? src/language/utilities/.dirstamp
? src/language/utilities/set.c
? src/language/xforms/.deps
? src/language/xforms/.dirstamp
? src/libpspp/.deps
? src/libpspp/.dirstamp
? src/libpspp/version.c
? src/math/.deps
? src/math/.dirstamp
? src/math/linreg/.deps
? src/math/linreg/.dirstamp
? src/math/ts/.deps
? src/math/ts/.dirstamp
? src/output/.deps
? src/output/.dirstamp
? src/output/charts/.deps
? src/output/charts/.dirstamp
? src/ui/.deps
? src/ui/.dirstamp
? src/ui/gui/.deps
? src/ui/gui/.dirstamp
? src/ui/gui/psppire
? src/ui/terminal/.deps
? src/ui/terminal/.dirstamp
? src/ui/terminal/pspp
? tests/libpspp/.deps
Index: src/data/casefile-private.h
===================================================================
RCS file: /sources/pspp/pspp/src/data/casefile-private.h,v
retrieving revision 1.1
diff -b -w -U3 -r1.1 casefile-private.h
--- src/data/casefile-private.h	17 Jul 2006 10:45:43 -0000	1.1
+++ src/data/casefile-private.h	18 Sep 2006 12:07:29 -0000
@@ -65,6 +65,8 @@
   unsigned long (*cnum) (const struct casereader *);
 
   void (*destroy) (struct casereader * r);
+
+  struct casereader * (*clone) (const struct casereader *);
 };
 
 
Index: src/data/casefile.c
===================================================================
RCS file: /sources/pspp/pspp/src/data/casefile.c,v
retrieving revision 1.15
diff -b -w -U3 -r1.15 casefile.c
--- src/data/casefile.c	17 Jul 2006 10:45:43 -0000	1.15
+++ src/data/casefile.c	18 Sep 2006 12:07:29 -0000
@@ -173,6 +173,13 @@
   r->class->destroy(r);
 }
 
+/* Creates a copy of R and returns it */
+struct casereader *
+casereader_clone(const struct casereader *r)
+{
+  return r->class->clone (r);
+}
+
 /* Destroys casefile CF. */
 void
 casefile_destroy(struct casefile *cf)
Index: src/data/casefile.h
===================================================================
RCS file: /sources/pspp/pspp/src/data/casefile.h,v
retrieving revision 1.4
diff -b -w -U3 -r1.4 casefile.h
--- src/data/casefile.h	17 Jul 2006 10:45:43 -0000	1.4
+++ src/data/casefile.h	18 Sep 2006 12:07:30 -0000
@@ -30,6 +30,7 @@
 struct casefile;
 
 
+/* Casereader functions */
 
 struct casefile *casereader_get_casefile (const struct casereader *r);
 
@@ -41,6 +42,11 @@
 
 void casereader_destroy (struct casereader *r);
 
+struct casereader *casereader_clone(const struct casereader *r);
+
+
+/* Casefile functions */
+
 void casefile_destroy (struct casefile *cf);
 
 bool casefile_error (const struct casefile *cf);
@@ -50,9 +56,8 @@
 size_t casefile_get_value_cnt (const struct casefile *cf);
 
 struct casereader *casefile_get_reader (const struct casefile *cf);
-struct casereader *casefile_get_destructive_reader (struct casefile *cf);
-
 
+struct casereader *casefile_get_destructive_reader (struct casefile *cf);
 
 bool casefile_append (struct casefile *cf, const struct ccase *c);
 
Index: src/data/dictionary.c
===================================================================
RCS file: /sources/pspp/pspp/src/data/dictionary.c,v
retrieving revision 1.13
diff -b -w -U3 -r1.13 dictionary.c
--- src/data/dictionary.c	2 Jul 2006 06:19:24 -0000	1.13
+++ src/data/dictionary.c	18 Sep 2006 12:07:30 -0000
@@ -691,7 +691,7 @@
    if an invalid weight is found. */
 double
 dict_get_case_weight (const struct dictionary *d, const struct ccase *c, 
-		      int *warn_on_invalid)
+		      bool *warn_on_invalid)
 {
   assert (d != NULL);
   assert (c != NULL);
@@ -704,7 +704,7 @@
       if (w < 0.0 || mv_is_num_missing (&d->weight->miss, w))
         w = 0.0;
       if ( w == 0.0 && *warn_on_invalid ) {
-	  *warn_on_invalid = 0;
+	  *warn_on_invalid = false;
 	  msg (SW, _("At least one case in the data file had a weight value "
 		     "that was user-missing, system-missing, zero, or "
 		     "negative.  These case(s) were ignored."));
Index: src/data/dictionary.h
===================================================================
RCS file: /sources/pspp/pspp/src/data/dictionary.h,v
retrieving revision 1.3
diff -b -w -U3 -r1.3 dictionary.h
--- src/data/dictionary.h	6 May 2006 22:37:30 -0000	1.3
+++ src/data/dictionary.h	18 Sep 2006 12:07:30 -0000
@@ -68,7 +68,7 @@
 struct ccase;
 struct variable *dict_get_weight (const struct dictionary *);
 double dict_get_case_weight (const struct dictionary *, 
-			     const struct ccase *, int *);
+			     const struct ccase *, bool *);
 void dict_set_weight (struct dictionary *, struct variable *);
 
 struct variable *dict_get_filter (const struct dictionary *);
Index: src/data/fastfile.c
===================================================================
RCS file: /sources/pspp/pspp/src/data/fastfile.c,v
retrieving revision 1.1
diff -b -w -U3 -r1.1 fastfile.c
--- src/data/fastfile.c	17 Jul 2006 10:45:43 -0000	1.1
+++ src/data/fastfile.c	18 Sep 2006 12:07:30 -0000
@@ -86,8 +86,7 @@
           also read with casereaders in this phase, but the
           ability to create new casereaders is curtailed.
 
-          In this phase, casereaders could still be cloned (once
-          we eventually implement cloning).
+          In this phase, casereaders could still be cloned.
 
           To transition from phase 1 or 2 to phase 3 and create a
           casereader, call casefile_get_destructive_reader().
@@ -287,6 +286,45 @@
   return reader;
 }
 
+
+/* Creates a copy of the casereader CR, and returns it */
+static struct casereader *
+fastfilereader_clone (const struct casereader *cr)
+{
+  const struct fastfilereader *ffr = (const struct fastfilereader *) cr ;
+  struct fastfilereader *new_ffr = xzalloc (sizeof *new_ffr);
+
+  struct casereader *new_reader = (struct casereader *) new_ffr;
+
+  struct casefile *cf =  casereader_get_casefile (cr);
+  struct fastfile *ff = (struct fastfile *) cf;
+
+  assert (!cf->being_destroyed);
+
+  /* Flush the buffer to disk if it's not empty. */
+  if (ff->mode == WRITE && ff->storage == DISK)
+    flush_buffer (ff);
+
+  ff->mode = READ;
+
+  casereader_register (cf, new_reader, &class_reader);
+
+  new_ffr->case_idx = ffr->case_idx ;
+  new_reader->destructive = cr->destructive;
+  new_ffr->fd = ffr->fd ;
+  new_ffr->buffer = ffr->buffer ;
+  new_ffr->buffer_pos = ffr->buffer_pos;
+  /*   case_clone (&new_ffr->c, &ffr->c); */
+
+  if (ff->storage == DISK)
+    reader_open_file (new_ffr);
+
+  return new_reader;
+}
+
+
+
+
 /* Returns the number of `union value's in a case for CF. */
 static size_t
 fastfile_get_value_cnt (const struct casefile *cf)
@@ -748,4 +786,5 @@
     fastfilereader_get_next_case,
     fastfilereader_cnum,
     fastfilereader_destroy,
+    fastfilereader_clone,
   };
Index: src/data/fastfile.h
===================================================================
RCS file: /sources/pspp/pspp/src/data/fastfile.h,v
retrieving revision 1.1
diff -b -w -U3 -r1.1 fastfile.h
--- src/data/fastfile.h	17 Jul 2006 10:45:43 -0000	1.1
+++ src/data/fastfile.h	18 Sep 2006 12:07:30 -0000
@@ -24,4 +24,5 @@
 
 struct casefile *fastfile_create (size_t value_cnt);
 
+
 #endif
Index: src/language/command.def
===================================================================
RCS file: /sources/pspp/pspp/src/language/command.def,v
retrieving revision 1.6
diff -b -w -U3 -r1.6 command.def
--- src/language/command.def	28 Jun 2006 18:40:21 -0000	1.6
+++ src/language/command.def	18 Sep 2006 12:07:31 -0000
@@ -109,6 +109,7 @@
 DEF_CMD (S_DATA, 0, "MODIFY VARS", cmd_modify_vars)
 DEF_CMD (S_DATA, 0, "ONEWAY", cmd_oneway)
 DEF_CMD (S_DATA, 0, "PEARSON CORRELATIONS", cmd_correlations)
+DEF_CMD (S_DATA, 0, "RANK", cmd_rank)
 DEF_CMD (S_DATA, 0, "REGRESSION", cmd_regression)
 DEF_CMD (S_DATA, 0, "RENAME VARIABLES", cmd_rename_variables)
 DEF_CMD (S_DATA, 0, "SAMPLE", cmd_sample)
@@ -177,7 +178,6 @@
 UNIMPL_CMD ("PROCEDURE OUTPUT", "Specify output file")
 UNIMPL_CMD ("PROXIMITIES", "Pairwise similarity")
 UNIMPL_CMD ("QUICK CLUSTER", "Fast clustering")
-UNIMPL_CMD ("RANK", "Create rank scores")
 UNIMPL_CMD ("RECORD TYPE", "Defines a type of record within FILE TYPE")
 UNIMPL_CMD ("REFORMAT", "Read obsolete files")
 UNIMPL_CMD ("REPEATING DATA", "Specify multiple cases per input record")
Index: src/language/stats/aggregate.c
===================================================================
RCS file: /sources/pspp/pspp/src/language/stats/aggregate.c,v
retrieving revision 1.13
diff -b -w -U3 -r1.13 aggregate.c
--- src/language/stats/aggregate.c	8 Jul 2006 03:05:51 -0000	1.13
+++ src/language/stats/aggregate.c	18 Sep 2006 12:07:33 -0000
@@ -743,7 +743,7 @@
 {
   struct agr_var *iter;
   double weight;
-  int bad_warn = 1;
+  bool bad_warn = 1;
 
   weight = dict_get_case_weight (default_dict, input, &bad_warn);
 
Index: src/language/stats/crosstabs.q
===================================================================
RCS file: /sources/pspp/pspp/src/language/stats/crosstabs.q,v
retrieving revision 1.13
diff -b -w -U3 -r1.13 crosstabs.q
--- src/language/stats/crosstabs.q	8 Jul 2006 03:05:51 -0000	1.13
+++ src/language/stats/crosstabs.q	18 Sep 2006 12:07:35 -0000
@@ -564,7 +564,7 @@
 static bool
 calc_general (const struct ccase *c, void *aux UNUSED)
 {
-  int bad_warn = 1;
+  bool bad_warn = 1;
 
   /* Case weight. */
   double weight = dict_get_case_weight (default_dict, c, &bad_warn);
@@ -638,7 +638,7 @@
 static bool
 calc_integer (const struct ccase *c, void *aux UNUSED)
 {
-  int bad_warn = 1;
+  bool bad_warn = 1;
 
   /* Case weight. */
   double weight = dict_get_case_weight (default_dict, c, &bad_warn);
Index: src/language/stats/descriptives.c
===================================================================
RCS file: /sources/pspp/pspp/src/language/stats/descriptives.c,v
retrieving revision 1.9
diff -b -w -U3 -r1.9 descriptives.c
--- src/language/stats/descriptives.c	27 Jun 2006 19:09:22 -0000	1.9
+++ src/language/stats/descriptives.c	18 Sep 2006 12:07:35 -0000
@@ -159,7 +159,7 @@
     /* Accumulated results. */
     double missing_listwise;    /* Sum of weights of cases missing listwise. */
     double valid;               /* Sum of weights of valid cases. */
-    int bad_warn;               /* Warn if bad weight found. */
+    bool bad_warn;              /* Warn if bad weight found. */
     enum dsc_statistic sort_by_stat; /* Statistic to sort by; -1: name. */
     int sort_ascending;         /* !0: ascending order; 0: descending. */
     unsigned long show_stats;   /* Statistics to display. */
Index: src/language/stats/examine.q
===================================================================
RCS file: /sources/pspp/pspp/src/language/stats/examine.q,v
retrieving revision 1.9
diff -b -w -U3 -r1.9 examine.q
--- src/language/stats/examine.q	5 Jul 2006 05:14:31 -0000	1.9
+++ src/language/stats/examine.q	18 Sep 2006 12:07:36 -0000
@@ -618,7 +618,7 @@
 
 
 
-static int bad_weight_warn = 1;
+static bool bad_weight_warn = 1;
 
 
 /* Perform calculations for the sub factors */
Index: src/language/stats/frequencies.q
===================================================================
RCS file: /sources/pspp/pspp/src/language/stats/frequencies.q,v
retrieving revision 1.13
diff -b -w -U3 -r1.13 frequencies.q
--- src/language/stats/frequencies.q	8 Jul 2006 03:05:51 -0000	1.13
+++ src/language/stats/frequencies.q	18 Sep 2006 12:07:37 -0000
@@ -509,7 +509,7 @@
 {
   double weight;
   size_t i;
-  int bad_warn = 1;
+  bool bad_warn = true;
 
   weight = dict_get_case_weight (default_dict, c, &bad_warn);
 
Index: src/language/stats/oneway.q
===================================================================
RCS file: /sources/pspp/pspp/src/language/stats/oneway.q,v
retrieving revision 1.9
diff -b -w -U3 -r1.9 oneway.q
--- src/language/stats/oneway.q	5 Jul 2006 05:14:31 -0000	1.9
+++ src/language/stats/oneway.q	18 Sep 2006 12:07:37 -0000
@@ -67,7 +67,7 @@
 
 
 
-static int bad_weight_warn = 1;
+static bool bad_weight_warn = true;
 
 
 static struct cmd_oneway cmd;
Index: src/language/stats/rank.q
===================================================================
RCS file: /sources/pspp/pspp/src/language/stats/rank.q,v
retrieving revision 1.10
diff -b -w -U3 -r1.10 rank.q
--- src/language/stats/rank.q	5 Jul 2006 05:14:31 -0000	1.10
+++ src/language/stats/rank.q	18 Sep 2006 12:07:38 -0000
@@ -1,7 +1,7 @@
 /* PSPP - RANK. -*-c-*-
 
-Copyright (C) 2005 Free Software Foundation, Inc.
-Author: John Darrington 2005
+Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+Author: John Darrington <john@darrington.wattle.id.au>
 
 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as
@@ -25,11 +25,18 @@
 #include <data/dictionary.h>
 #include <data/procedure.h>
 #include <data/variable.h>
+#include <data/case.h>
+#include <data/casefile.h>
+#include <data/fastfile.h>
+#include <data/storage-stream.h>
 #include <language/command.h>
 #include <language/stats/sort-criteria.h>
 #include <libpspp/compiler.h>
 #include <math/sort.h>
 
+
+#include <gsl/gsl_cdf.h>
+
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
@@ -47,13 +54,13 @@
    +n=custom;
    +savage=custom;
    +print=print:!yes/no;
+   +fraction=fraction:!blom/tukey/vw/rankit;
+   +ties=ties:!mean/low/high/condense;
    missing=miss:!exclude/include.
 */
 /* (declarations) */
 /* (functions) */
 
-
-
 enum RANK_FUNC
   {
     RANK,
@@ -64,6 +71,41 @@
     N,
     NTILES,
     SAVAGE,
+    n_RANK_FUNCS
+  };
+
+
+typedef double (*rank_function_t) (double c, double cc, double cc_1, 
+				 int i, double w);
+
+static double rank_proportion (double c, double cc, double cc_1, 
+			       int i, double w);
+
+static double rank_normal (double c, double cc, double cc_1, 
+			   int i, double w);
+
+static double rank_percent (double c, double cc, double cc_1, 
+			    int i, double w);
+
+static double rank_rfraction (double c, double cc, double cc_1, 
+			      int i, double w);
+
+static double rank_rank (double c, double cc, double cc_1, 
+			 int i, double w);
+
+static double rank_n (double c, double cc, double cc_1, 
+		      int i, double w);
+
+
+static rank_function_t rank_func[n_RANK_FUNCS] = {
+  rank_rank,
+  rank_normal,
+  rank_percent,
+  rank_rfraction,
+  rank_proportion,
+  rank_n,
+  0, /* ntiles */
+  0  /* savage */
   };
 
 
@@ -85,6 +127,335 @@
 
 static struct cmd_rank cmd;
 
+static struct casefile *rank_sorted_casefile (const struct casefile *cf, 
+					      struct sort_criterion *crit, 
+					      const struct rank_spec *rs, 
+					      int n_rank_specs,
+					      int idx
+					      );
+
+static bool 
+rank_cmd (const struct sort_criteria *sc, 
+      const struct rank_spec *rank_specs, int n_rank_specs)
+{
+  bool result = true;
+  int i;
+
+  for (i = 0 ; i < sc->crit_cnt ; ++i )
+    {
+      struct casefile *out ;
+      struct casefile *cf ; 
+      struct sort_criterion *crit = &sc->crits[i];
+      struct casereader *reader ;
+      struct casefile *sorted_cf ;
+
+      if (!procedure (NULL, NULL))
+	return false;
+
+      cf = proc_capture_output ();
+
+      reader = casefile_get_destructive_reader (cf) ;
+      sorted_cf = sort_execute (reader, sort_criteria_single (crit) );
+
+      out = rank_sorted_casefile (sorted_cf, crit, rank_specs, n_rank_specs, i)  ;
+      if ( NULL == out ) 
+	{
+	  result = false ;
+	  continue ;
+	}
+      
+      proc_set_source (storage_source_create (out));
+    }
+
+  return result ; 
+}
+
+
+/* A function to be called as payload to rank_iterate.
+   CCASE is the current case.  FV is the index passed to rank_iterate.
+   C is sum of the weights for the current case and all cases with equal 
+   values.
+   CC is the cumulative C values up to and including this case.
+   CC_1 is CC - C .
+   I is an iteration variable starting at 1
+   AUX is the auxiliary data passed into rank_iterate.
+ */
+typedef void (*ordinal_func_t) (const struct ccase *ccase, int fv,
+				double c, double cc, double cc_1, 
+				unsigned long i, void *aux);
+
+
+/* Iterate the casefile CF, executing PAYLOAD for each case or, if
+   DISTINCT is true, then PAYLOAD is called only for distinct values.  
+   AUX is data passed to PAYLOAD.
+
+   Prerequisite: CF must be sorted (ascending or descending) by the value 
+   at FV.
+*/
+static void
+rank_iterate (const struct casefile *cf, int fv, 
+	      ordinal_func_t payload, void *aux, 
+	      bool distinct
+	      )
+{
+  static double w = -1.0;
+  double cc = 0.0;
+  double cc_1 ; 
+  struct casereader *r;
+  struct ccase this_case;
+  unsigned long n = 1;
+  bool warn = true;
+  int diff_sign = 0.0;
+  unsigned long i = 1;
+
+  for(r = casefile_get_reader (cf);
+      casereader_read (r, &this_case);)
+    {
+      struct ccase next_case ;
+      struct casereader *rc = casereader_clone (r);
+      const union value *this_value = case_data (&this_case, fv);
+
+      if ( n > 1 ) 
+	{
+	  n--; 
+	  if ( ! distinct ) 
+	    payload (&this_case, fv, w, cc, cc_1, i++, aux);
+	  continue;
+	}
+
+      w = dict_get_case_weight (default_dict, &this_case, &warn);
+      
+      while ( casereader_read (rc, &next_case) )
+	{
+	  const union value *next_value = case_data (&next_case, fv);
+	  const int diff = compare_values (this_value, next_value, 0); 
+	  if ( 0 != diff ) 
+	    {
+	      const int this_sign = (diff > 0) ? +1 : -1;
+	      if ( diff_sign != 0 && this_sign != diff_sign ) 
+		NOT_REACHED ();  /* occurs if the casefile is not sorted */
+	      diff_sign = this_sign ;
+	      
+	      break;
+	    }
+	  w += dict_get_case_weight (default_dict, &next_case, &warn);
+	  n++;
+	}
+
+      cc_1 = cc;
+      cc += w;
+
+      payload (&this_case, fv, w, cc, cc_1, i++, aux);
+
+      casereader_destroy (rc);
+    }
+}
+
+
+/* Hardly a rank function !! */
+static double 
+rank_n (double c UNUSED, double cc UNUSED, double cc_1 UNUSED, 
+	  int i UNUSED, double w)
+{
+  return w;
+}
+
+
+static double 
+rank_rank (double c, double cc, double cc_1, 
+	  int i, double w UNUSED)
+{
+  double rank;
+  if ( c >= 1.0 ) 
+    {
+      switch (cmd.ties)
+	{
+	case RANK_LOW:
+	  rank = cc_1 + 1;
+	  break;
+	case RANK_HIGH:
+	  rank = cc;
+	  break;
+	case RANK_MEAN:
+	  rank = cc_1 + (c + 1.0)/ 2.0;
+	  break;
+	case RANK_CONDENSE:
+	  rank = i;
+	  break;
+	default:
+	  NOT_REACHED ();
+	}
+    }
+  else
+    {
+      switch (cmd.ties)
+	{
+	case RANK_LOW:
+	  rank = cc_1;
+	  break;
+	case RANK_HIGH:
+	  rank = cc;
+	  break;
+	case RANK_MEAN:
+	  rank = cc_1 + c / 2.0 ;
+	  break;
+	case RANK_CONDENSE:
+	  rank = i;
+	  break;
+	default:
+	  NOT_REACHED ();
+	}
+    }
+
+  return rank;
+}
+
+
+static double 
+rank_rfraction (double c, double cc, double cc_1, 
+		int i, double w)
+{
+  return rank_rank (c, cc, cc_1, i, w) / w ;
+}
+
+
+static double 
+rank_percent (double c, double cc, double cc_1, 
+		int i, double w)
+{
+  return rank_rank (c, cc, cc_1, i, w) * 100.0 / w ;
+}
+
+
+static double 
+rank_proportion (double c, double cc, double cc_1, 
+		 int i, double w)
+{
+  const double r =  rank_rank (c, cc, cc_1, i, w) ;
+
+  double f;
+  
+  switch ( cmd.fraction ) 
+    {
+    case RANK_BLOM:
+      f =  (r - 3.0/8.0) / (w + 0.25);
+      break;
+    case RANK_RANKIT:
+      f = (r - 0.5) / w ;
+      break;
+    case RANK_TUKEY:
+      f = (r - 1.0/3.0) / (w + 1.0/3.0);
+      break;
+    case RANK_VW:
+      f = r / ( w + 1.0);
+      break;
+    default:
+      NOT_REACHED ();
+    }
+
+
+  return (f > 0) ? f : SYSMIS;
+}
+
+static double 
+rank_normal (double c, double cc, double cc_1, 
+	     int i, double w)
+{
+  double f = rank_proportion (c, cc, cc_1, i, w);
+  
+  return gsl_cdf_ugaussian_Pinv (f);
+}
+
+
+
+
+static void
+sum_caseweights (const struct ccase *this_case UNUSED, int fv UNUSED, 
+		 double c, double cc UNUSED, double cc_1 UNUSED,
+		 unsigned long i UNUSED, void *aux)
+
+{
+  double *w = aux;
+
+  *w += c;
+}
+
+
+struct rank_proc
+{
+  struct casefile *dest;
+  struct sort_criterion *crit;
+  const struct rank_spec *rs;
+  int n_rank_specs;
+  int idx;
+  double w;
+};
+
+static void
+rank_it (const struct ccase *this_case, int fv UNUSED, 
+	 double c, double cc UNUSED, double cc_1,
+	 unsigned long iter UNUSED, void *aux)
+{
+  int i;
+  struct ccase new_case;
+  
+  struct rank_proc *mything = aux;
+
+  case_clone (&new_case, this_case);
+
+  for ( i = 0 ; i < mything->n_rank_specs  ; ++i ) 
+    {
+
+      const int dest_idx = mything->rs[i].destvars[mything->idx]->fv;
+
+      case_data_rw (&new_case, dest_idx)->f = 
+	rank_func[mything->rs[i].rfunc](c, cc, cc_1, iter, mything->w)  ;
+
+    }
+      
+  casefile_append_xfer (mything->dest, &new_case);
+  assert ( ! casefile_error (mything->dest) );
+}
+
+
+static struct casefile *
+rank_sorted_casefile (const struct casefile *cf, 
+		      struct sort_criterion *crit, 
+		      const struct rank_spec *rs, 
+		      int n_rank_specs, 
+		      int idx)
+{
+  struct rank_proc mything;
+
+  mything.dest = fastfile_create (casefile_get_value_cnt (cf));
+  mything.crit = crit;
+  mything.rs = rs;
+  mything.n_rank_specs = n_rank_specs;
+  mything.idx = idx;
+  mything.w = 0.0;
+
+  /* Rank functions other than RANK, need to know 
+     the sum of all the caseweights */
+  if ( cmd.sbc_normal    || cmd.sbc_ntiles || cmd.sbc_proportion || 
+       cmd.sbc_rfraction || cmd.sbc_savage || cmd.sbc_n ) 
+      rank_iterate (cf, crit->fv, sum_caseweights, &mything.w, true);
+
+  rank_iterate (cf, crit->fv, rank_it, &mything, false);
+
+  return mything.dest;
+}
+
+
+/* Transformation function to enumerate all the cases */
+static int 
+create_resort_key (void *key_var_, struct ccase *cc, int case_num)
+{
+  struct variable *key_var = key_var_;
+
+  case_data_rw(cc, key_var->fv)->f = case_num;
+  
+  return TRNS_CONTINUE;
+}
 
 
 int cmd_rank(void);
@@ -92,33 +463,48 @@
 int
 cmd_rank(void)
 {
+  struct variable *order;
   size_t i;
   n_rank_specs = 0;
 
   if ( !parse_rank(&cmd, NULL) )
     return CMD_FAILURE;
 
+  /* Default to /RANK if no function subcommands are given */
+  if ( !( cmd.sbc_normal    || cmd.sbc_ntiles || cmd.sbc_proportion || 
+	  cmd.sbc_rfraction || cmd.sbc_savage || cmd.sbc_n || cmd.sbc_rank ) )
+    cmd.sbc_rank++;
+
+  if ( cmd.sbc_fraction && 
+       ( ! cmd.sbc_normal && ! cmd.sbc_proportion) )
+    msg(MW, _("FRACTION has been specified, but NORMAL and PROPORTION rank functions have not been requested.  The FRACTION subcommand will be ignored.") );
+
 #if 1
-  for (i = 0 ; i <  sc->crit_cnt ; ++i )
-    {
-      struct sort_criterion *crit = &sc->crits[i];
+  for (i = 0 ; i < n_group_vars ; ++i )
+    printf ("Ignoring group var: %s\n", group_vars[i]->name);
+#endif
       
-      printf("Dir: %d; Index: %d\n", crit->dir, crit->fv);
-    }
+  /* Add a variable which we can sort by to get back the original
+     order */
+  order = dict_create_var_assert (default_dict, "$ORDER_", 0);
 
-  for (i = 0 ; i <  n_group_vars ; ++i )
-    printf("Group var: %s\n",group_vars[0]->name);
+  add_transformation (create_resort_key, 0, order);
 
-  for (i = 0 ; i <  n_rank_specs ; ++i )
+  /* Do the ranking */
+  rank_cmd (sc, rank_specs, n_rank_specs);
+
+  /* Put the active file back in its original order */
     {
-      int j;
-      printf("Ranks spec %d; Func: %d\n",i, rank_specs[i].rfunc);
+    struct sort_criterion restore_criterion ;
+    restore_criterion.fv = order->fv;
+    restore_criterion.width = 0;
+    restore_criterion.dir = SRT_ASCEND;
       
-      for (j=0; j < sc->crit_cnt ; ++j )
-	printf("Dest var is \"%s\"\n", rank_specs[i].destvars[j]->name);
+    sort_active_file_in_place (sort_criteria_single (&restore_criterion)) ;
     }
-#endif 
 
+  /* ... and we don't need our sort key anymore. So delete it */
+  dict_delete_var (default_dict, order);
 
   free(group_vars);
   
@@ -169,6 +555,43 @@
   return 1;
 }
 
+static char *
+create_var_label (const char *ranked_var_name, enum RANK_FUNC f)
+{
+  const int lsize = 5 + strlen(ranked_var_name) + 10 ;
+  char *label  = xmalloc ( lsize ) ;
+  switch ( f ) 
+    {
+    case RANK:
+      snprintf (label, lsize, "RANK of %s", ranked_var_name);
+      break;
+    case NORMAL:
+      snprintf (label, lsize, "NORMAL of %s", ranked_var_name);
+      break;
+    case PERCENT:
+      snprintf (label, lsize, "PERCENT of %s", ranked_var_name);
+      break;
+    case PROPORTION:
+      snprintf (label, lsize, "PERCENT of %s", ranked_var_name);
+      break;
+    case N:
+      snprintf (label, lsize, "N of %s", ranked_var_name);
+      break;
+    case NTILES:
+      snprintf (label, lsize, "NTILES of %s", ranked_var_name);
+      break;
+    case RFRACTION:
+      snprintf (label, lsize, "RFRACTION of %s", ranked_var_name);
+      break;
+    case SAVAGE:
+      snprintf (label, lsize, "RFRACTION of %s", ranked_var_name);
+      break;
+    default:
+      NOT_REACHED ();
+    }
+
+  return label;
+}
 
 /* Return a name for a new variable which ranks the variable VAR_NAME,
    according to the ranking function F.
@@ -186,27 +609,31 @@
       switch (f) 
 	{
 	case RANK:
+	  strcpy (new_name,"RAN");
+	  break;
 	case RFRACTION:
-	  strcpy(new_name,"R");
+	  strcpy (new_name,"RFA");
 	  break;
-
 	case NORMAL:
+	  strcpy (new_name,"NOR");
+	  break;
 	case N:
-	case NTILES:
 	  strcpy(new_name,"N");
 	  break;
-      
+	case NTILES:
+	  strcpy (new_name,"NTI");
+	  break;
 	case PERCENT:
+	  strcpy (new_name,"PER");
+	  break;
 	case PROPORTION:
-	  strcpy(new_name,"P");
+	  strcpy (new_name,"PRO");
 	  break;
-
 	case SAVAGE:
-	  strcpy(new_name,"S");
+	  strcpy (new_name,"SAV");
 	  break;
-
 	default:
-	  assert(false);
+	  NOT_REACHED ();
 	  break;
 	}
   
@@ -270,7 +697,7 @@
      variables assigned */
   while (var_count < sc->crit_cnt)
     {
-      static int idx=0;
+      int idx = 0;
       struct variable *destvar ; 
       const struct variable *v = dict_get_var(default_dict,
 					      sc->crits[var_count].fv);
@@ -281,7 +708,9 @@
 	new_name = new_variable_name(v->name, f, idx);
 
 	destvar = dict_create_var (default_dict, new_name, 0);
-	if (!destvar ) 
+	if (destvar )
+	  destvar->label = create_var_label (v->name, f);
+	else
 	  ++idx;
 
       } while( !destvar ) ;
@@ -312,7 +741,7 @@
 static int
 rank_custom_percent(struct cmd_rank *cmd, void *aux UNUSED )
 {
-  return parse_rank_function(cmd, NORMAL);
+  return parse_rank_function (cmd, PERCENT);
 }
 
 static int
@@ -359,4 +788,3 @@
   return parse_rank_function(cmd, NTILES);
 }
 
-
Index: src/language/stats/t-test.q
===================================================================
RCS file: /sources/pspp/pspp/src/language/stats/t-test.q,v
retrieving revision 1.10
diff -b -w -U3 -r1.10 t-test.q
--- src/language/stats/t-test.q	8 Jul 2006 03:05:51 -0000	1.10
+++ src/language/stats/t-test.q	18 Sep 2006 12:07:38 -0000
@@ -242,7 +242,7 @@
 
 static struct cmd_t_test cmd;
 
-static int bad_weight_warn;
+static bool bad_weight_warn;
 
 
 static int compare_group_binary(const struct group_statistics *a, 
Index: src/math/levene.c
===================================================================
RCS file: /sources/pspp/pspp/src/math/levene.c,v
retrieving revision 1.3
diff -b -w -U3 -r1.3 levene.c
--- src/math/levene.c	5 May 2006 04:53:13 -0000	1.3
+++ src/math/levene.c	18 Sep 2006 12:07:39 -0000
@@ -187,7 +187,7 @@
 levene_calc (const struct ccase *c, void *_l)
 {
   size_t i;
-  int warn = 0;
+  bool warn = 0;
   struct levene_info *l = (struct levene_info *) _l;
   const union value *gv = case_data (c, l->v_indep->fv);
   struct group_statistics key;
@@ -291,7 +291,7 @@
 levene2_calc (const struct ccase *c, void *_l)
 {
   size_t i;
-  int warn = 0;
+  bool warn = 0;
 
   struct levene_info *l = (struct levene_info *) _l;
 
Index: src/math/sort.c
===================================================================
RCS file: /sources/pspp/pspp/src/math/sort.c,v
retrieving revision 1.12
diff -b -w -U3 -r1.12 sort.c
--- src/math/sort.c	17 Jul 2006 10:45:43 -0000	1.12
+++ src/math/sort.c	18 Sep 2006 12:07:39 -0000
@@ -59,6 +59,22 @@
 static struct casefile *do_external_sort (struct casereader *,
                                           const struct sort_criteria *);
 
+/* Return a pointer to a struct sort_criteria which comprises the 
+   single criterion SC .
+   The pointer will be valid until the next call to this function .
+*/
+const struct sort_criteria * 
+sort_criteria_single ( struct sort_criterion *sc)
+{
+  static struct sort_criteria criteria;
+
+  criteria.crit_cnt = 1;
+  criteria.crits = sc;
+
+  return &criteria ;
+}
+
+
 /* Get ready to sort the active file. */
 static void
 prepare_to_sort_active_file (void) 
@@ -67,23 +83,24 @@
 }
 
 /* Sorts the active file in-place according to CRITERIA.
-   Returns nonzero if successful. */
-int
+   Returns true if successful. */
+bool
 sort_active_file_in_place (const struct sort_criteria *criteria) 
 {
   struct casefile *in, *out;
 
   prepare_to_sort_active_file ();
+
   if (!procedure (NULL, NULL))
-    return 0;
+    return false;
   
   in = proc_capture_output ();
   out = sort_execute (casefile_get_destructive_reader (in), criteria);
   if (out == NULL) 
-    return 0;
+    return false;
 
   proc_set_source (storage_source_create (out));
-  return 1;
+  return true;
 }
 
 /* Data passed to sort_to_casefile_callback(). */
Index: src/math/sort.h
===================================================================
RCS file: /sources/pspp/pspp/src/math/sort.h,v
retrieving revision 1.1
diff -b -w -U3 -r1.1 sort.h
--- src/math/sort.h	4 Mar 2006 01:11:57 -0000	1.1
+++ src/math/sort.h	18 Sep 2006 12:07:39 -0000
@@ -54,13 +54,14 @@
     size_t crit_cnt;
   };
 
+const struct sort_criteria *sort_criteria_single (struct sort_criterion *sc);
 
 void sort_destroy_criteria (struct sort_criteria *);
 
 struct casefile *sort_execute (struct casereader *,
                                const struct sort_criteria *);
 
-int sort_active_file_in_place (const struct sort_criteria *);
+bool sort_active_file_in_place (const struct sort_criteria *);
 
 struct casefile *sort_active_file_to_casefile (const struct sort_criteria *);
 
Index: src/ui/flexifile.c
===================================================================
RCS file: /sources/pspp/pspp/src/ui/flexifile.c,v
retrieving revision 1.1
diff -b -w -U3 -r1.1 flexifile.c
--- src/ui/flexifile.c	17 Jul 2006 10:45:43 -0000	1.1
+++ src/ui/flexifile.c	18 Sep 2006 12:07:39 -0000
@@ -212,6 +212,24 @@
   return reader;
 }
 
+
+static struct casereader *
+flexifilereader_clone (const struct casereader *cr)
+{
+  const struct flexifilereader *ffr = (const struct flexifilereader *) cr;
+  struct flexifilereader *new_ffr = xzalloc (sizeof *new_ffr);
+  struct casereader *new_reader = (struct casereader *) new_ffr;
+  struct casefile *cf = casereader_get_casefile (cr);
+
+  casereader_register (cf, new_reader, CLASS_CASEREADER(&class_reader));
+
+  new_ffr->case_idx = ffr->case_idx ;
+  new_ffr->destructive = ffr->destructive ;
+
+  return new_reader;
+}
+
+
 static bool
 flexifile_in_core(const struct casefile *cf UNUSED)
 {
@@ -268,7 +286,8 @@
     {
       flexifilereader_get_next_case,
       0,  /* cnum */
-      flexifilereader_destroy
+      flexifilereader_destroy,
+      flexifilereader_clone
     }
   };
 
