pspp-cvs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Pspp-cvs] pspp/src ui/gui/val-labs-dialog.h math/sort.c d... [simpler-p


From: Ben Pfaff
Subject: [Pspp-cvs] pspp/src ui/gui/val-labs-dialog.h math/sort.c d... [simpler-proc]
Date: Sun, 06 May 2007 22:48:28 +0000

CVSROOT:        /cvsroot/pspp
Module name:    pspp
Branch:         simpler-proc
Changes by:     Ben Pfaff <blp> 07/05/06 22:48:28

Modified files:
        src/ui/gui     : val-labs-dialog.h 
        src/math       : sort.c 
        src/data       : procedure.h casewriter.c casewindow.c 
                         casereader.h casereader.c case-tmpfile.h 
                         case-tmpfile.c automake.mk 
Added files:
        src/data       : casereader-translator.c casereader-filter.c 

Log message:
        Start cleaning up code.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/pspp/src/ui/gui/val-labs-dialog.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.6&r2=1.6.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/math/sort.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.23.2.2&r2=1.23.2.3
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/procedure.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.12.2.2&r2=1.12.2.3
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/casewriter.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.1.2.3&r2=1.1.2.4
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/casewindow.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.1.2.4&r2=1.1.2.5
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/casereader.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.1.2.3&r2=1.1.2.4
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/casereader.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.1.2.5&r2=1.1.2.6
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/case-tmpfile.h?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.1.2.2&r2=1.1.2.3
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/case-tmpfile.c?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.1.2.4&r2=1.1.2.5
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/automake.mk?cvsroot=pspp&only_with_tag=simpler-proc&r1=1.15.2.2&r2=1.15.2.3
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/casereader-translator.c?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1
http://cvs.savannah.gnu.org/viewcvs/pspp/src/data/casereader-filter.c?cvsroot=pspp&only_with_tag=simpler-proc&rev=1.1.2.1

Patches:
Index: ui/gui/val-labs-dialog.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/ui/gui/val-labs-dialog.h,v
retrieving revision 1.6
retrieving revision 1.6.2.1
diff -u -b -r1.6 -r1.6.2.1
--- ui/gui/val-labs-dialog.h    24 Dec 2006 23:50:59 -0000      1.6
+++ ui/gui/val-labs-dialog.h    6 May 2007 22:48:27 -0000       1.6.2.1
@@ -29,6 +29,7 @@
 
 #include <gtk/gtk.h>
 #include <glade/glade.h>
+#include <data/variable.h>
 
 
 struct val_labs;

Index: math/sort.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/math/sort.c,v
retrieving revision 1.23.2.2
retrieving revision 1.23.2.3
diff -u -b -r1.23.2.2 -r1.23.2.3
--- math/sort.c 4 May 2007 03:48:48 -0000       1.23.2.2
+++ math/sort.c 6 May 2007 22:48:27 -0000       1.23.2.3
@@ -139,9 +139,6 @@
   casenumber min_run_id;
 
   pqueue_pop (sort->pqueue, &min_case, &min_run_id);
-#if 0
-  printf ("\toutput: %f to run %d\n", case_num_idx (&min_case, 0), min_run_id);
-#endif
 
   if (sort->run_id != min_run_id && sort->run != NULL) 
     {

Index: data/procedure.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/procedure.h,v
retrieving revision 1.12.2.2
retrieving revision 1.12.2.3
diff -u -b -r1.12.2.2 -r1.12.2.3
--- data/procedure.h    4 May 2007 03:48:47 -0000       1.12.2.2
+++ data/procedure.h    6 May 2007 22:48:27 -0000       1.12.2.3
@@ -72,7 +72,7 @@
 
 struct casereader *proc_open (struct dataset *);
 bool proc_is_open (const struct dataset *);
-bool proc_commit (struct dataset *) WARN_UNUSED_RESULT;
+bool proc_commit (struct dataset *);
 
 bool dataset_end_of_command (struct dataset *);
 

Index: data/casewriter.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/Attic/casewriter.c,v
retrieving revision 1.1.2.3
retrieving revision 1.1.2.4
diff -u -b -r1.1.2.3 -r1.1.2.4
--- data/casewriter.c   4 May 2007 03:48:47 -0000       1.1.2.3
+++ data/casewriter.c   6 May 2007 22:48:27 -0000       1.1.2.4
@@ -54,11 +54,10 @@
 }
 
 struct casewriter *
-casewriter_rename (struct casewriter *old)
+casewriter_rename (struct casewriter *writer)
 {
-  struct casewriter *new = xmalloc (sizeof *old);
-  *new = *old;
-  free (old);
+  struct casewriter *new = xmemdup (writer, sizeof *writer);
+  free (writer);
   return new;
 }
 

Index: data/casewindow.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/Attic/casewindow.c,v
retrieving revision 1.1.2.4
retrieving revision 1.1.2.5
diff -u -b -r1.1.2.4 -r1.1.2.5
--- data/casewindow.c   4 May 2007 03:48:47 -0000       1.1.2.4
+++ data/casewindow.c   6 May 2007 22:48:27 -0000       1.1.2.5
@@ -42,10 +42,10 @@
 
 struct casewindow_class 
   {
-    void *(*create) (size_t value_cnt);
-    bool (*destroy) (void *aux);
-    bool (*push_head) (void *aux, struct ccase *);
-    bool (*pop_tail) (void *aux, casenumber cnt);
+    void *(*create) (struct taint *, size_t value_cnt);
+    void (*destroy) (void *aux);
+    void (*push_head) (void *aux, struct ccase *);
+    void (*pop_tail) (void *aux, casenumber cnt);
     bool (*get_case) (void *aux, casenumber ofs, struct ccase *);
     casenumber (*get_case_cnt) (const void *aux);
   };
@@ -61,7 +61,7 @@
   cw->class = (max_in_core_cases
               ? &casewindow_memory_class
               : &casewindow_file_class);
-  cw->aux = cw->class->create (value_cnt);
+  cw->aux = cw->class->create (taint, value_cnt);
   cw->value_cnt = value_cnt;
   cw->max_in_core_cases = max_in_core_cases;
   cw->taint = taint;
@@ -80,8 +80,8 @@
   bool ok = true;
   if (cw != NULL) 
     {
-      ok = cw->class->destroy (cw->aux);
-      ok = taint_destroy (cw->taint) && ok;
+      cw->class->destroy (cw->aux);
+      ok = taint_destroy (cw->taint);
       free (cw);
     }
   return ok;
@@ -117,15 +117,14 @@
 {
   if (!casewindow_error (cw))
     {
-      if (cw->class->push_head (cw->aux, c)) 
+      cw->class->push_head (cw->aux, c);
+      if (!casewindow_error (cw))
         {
           casenumber case_cnt = cw->class->get_case_cnt (cw->aux);
           if (case_cnt > cw->max_in_core_cases
               && cw->class == &casewindow_memory_class)
             casewindow_to_disk (cw); 
         }
-      else
-        casewindow_force_error (cw);
     }
   else
     case_destroy (c);
@@ -135,8 +134,7 @@
 casewindow_pop_tail (struct casewindow *cw, casenumber case_cnt) 
 {
   if (!casewindow_error (cw))
-    if (!cw->class->pop_tail (cw->aux, case_cnt))
-      casewindow_force_error (cw);
+    cw->class->pop_tail (cw->aux, case_cnt);
 }
 
 bool
@@ -146,11 +144,10 @@
   struct casewindow *cw = (struct casewindow *) cw_;
 
   assert (case_idx >= 0 && case_idx < casewindow_get_case_cnt (cw));
-  if (!casewindow_error (cw) && cw->class->get_case (cw->aux, case_idx, c))
-    return true;
+  if (!casewindow_error (cw))
+    return cw->class->get_case (cw->aux, case_idx, c);
   else 
     {
-      casewindow_force_error (cw);
       case_nullify (c);
       return false;
     }
@@ -193,14 +190,14 @@
   };
 
 static void *
-casewindow_memory_create (size_t value_cnt UNUSED) 
+casewindow_memory_create (struct taint *taint UNUSED, size_t value_cnt UNUSED) 
 {
   struct casewindow_memory *cwm = xmalloc (sizeof *cwm);
   cwm->cases = deque_init (&cwm->deque, 4, sizeof *cwm->cases);
   return cwm;
 }
 
-static bool
+static void
 casewindow_memory_destroy (void *cwm_) 
 {
   struct casewindow_memory *cwm = cwm_;
@@ -208,27 +205,24 @@
     case_destroy (&cwm->cases[deque_pop_front (&cwm->deque)]);
   free (cwm->cases);
   free (cwm);
-  return true;
 }
 
-static bool
+static void
 casewindow_memory_push_head (void *cwm_, struct ccase *c)
 {
   struct casewindow_memory *cwm = cwm_;
   if (deque_is_full (&cwm->deque))
     cwm->cases = deque_expand (&cwm->deque, cwm->cases, sizeof *cwm->cases);
   case_move (&cwm->cases[deque_push_back (&cwm->deque)], c);
-  return true;
 }
 
-static bool
+static void
 casewindow_memory_pop_tail (void *cwm_, casenumber case_cnt)
 {
   struct casewindow_memory *cwm = cwm_;
   assert (deque_count (&cwm->deque) >= case_cnt);
   while (case_cnt-- > 0) 
     case_destroy (&cwm->cases[deque_pop_front (&cwm->deque)]);
-  return true;
 }
 
 static bool
@@ -263,37 +257,32 @@
   };
 
 static void *
-casewindow_file_create (size_t value_cnt) 
+casewindow_file_create (struct taint *taint, size_t value_cnt) 
 {
   struct casewindow_file *cwf = xmalloc (sizeof *cwf);
   cwf->file = case_tmpfile_create (value_cnt);
   cwf->head = cwf->tail = 0;
+  taint_propagate (case_tmpfile_get_taint (cwf->file), taint);
   return cwf;
 }
 
-static bool
+static void
 casewindow_file_destroy (void *cwf_) 
 {
   struct casewindow_file *cwf = cwf_;
-  bool ok = case_tmpfile_destroy (cwf->file);
+  case_tmpfile_destroy (cwf->file);
   free (cwf);
-  return ok;
 }
 
-static bool
+static void
 casewindow_file_push_head (void *cwf_, struct ccase *c) 
 {
   struct casewindow_file *cwf = cwf_;
   if (case_tmpfile_put_case (cwf->file, cwf->head, c)) 
-    {
       cwf->head++;
-      return true;
-    }
-  else
-    return false;
 }
 
-static bool
+static void
 casewindow_file_pop_tail (void *cwf_, casenumber cnt) 
 {
   struct casewindow_file *cwf = cwf_;
@@ -301,7 +290,6 @@
   cwf->tail += cnt;
   if (cwf->head == cwf->tail)
     cwf->head = cwf->tail = 0;
-  return true;
 }
 
 static bool

Index: data/casereader.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/Attic/casereader.h,v
retrieving revision 1.1.2.3
retrieving revision 1.1.2.4
diff -u -b -r1.1.2.3 -r1.1.2.4
--- data/casereader.h   4 May 2007 03:48:47 -0000       1.1.2.3
+++ data/casereader.h   6 May 2007 22:48:27 -0000       1.1.2.4
@@ -34,6 +34,7 @@
 void casereader_split (struct casereader *,
                        struct casereader **, struct casereader **);
 struct casereader *casereader_rename (struct casereader *);
+void casereader_swap (struct casereader *, struct casereader *);
 
 bool casereader_peek (struct casereader *, casenumber, struct ccase *)
      WARN_UNUSED_RESULT;

Index: data/casereader.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/Attic/casereader.c,v
retrieving revision 1.1.2.5
retrieving revision 1.1.2.6
diff -u -b -r1.1.2.5 -r1.1.2.6
--- data/casereader.c   4 May 2007 03:48:47 -0000       1.1.2.5
+++ data/casereader.c   6 May 2007 22:48:27 -0000       1.1.2.6
@@ -21,58 +21,77 @@
 #include <data/casereader.h>
 #include <data/casereader-private.h>
 
-#include <assert.h>
 #include <stdlib.h>
 
 #include <data/buffered-reader.h>
 #include <data/casewindow.h>
 #include <data/casewriter.h>
-#include <data/dictionary.h>
 #include <data/settings.h>
-#include <data/variable.h>
-#include <libpspp/message.h>
+#include <libpspp/assertion.h>
 #include <libpspp/taint.h>
 
 #include "xalloc.h"
 
-#include "gettext.h"
-#define _(msgid) gettext (msgid)
-
+/* A casereader. */
 struct casereader 
   {
-    struct taint *taint;
-    size_t value_cnt;
-    casenumber case_cnt;
-    const struct casereader_class *class;
-    void *aux;
+    struct taint *taint;                  /* Corrupted? */
+    size_t value_cnt;                     /* Values per case. */
+    casenumber case_cnt;                  /* Number of cases,
+                                             CASENUMBER_MAX if unknown. */
+    const struct casereader_class *class; /* Class. */
+    void *aux;                            /* Auxiliary data for class. */
   };
 
 static void insert_casereader_buffer (struct casereader *);
 
-struct casereader *
-casereader_rename (struct casereader *old) 
+/* Creates a new case in C and reads the next case from READER
+   into it.  The caller owns C and must destroy C when its data
+   is no longer needed.  Return true if successful, false when
+   cases have been exhausted or upon detection of an I/O error.
+   In the latter case, C is set to the null case.
+
+   The case returned is effectively consumed: it can never be
+   read again through READER.  If this is inconvenient, READER
+   may be cloned in advance with casereader_clone, or
+   casereader_peek may be used instead. */
+bool
+casereader_read (struct casereader *reader, struct ccase *c) 
 {
-  struct casereader *new = xmalloc (sizeof *old);
-  *new = *old;
-  free (old);
-  return new;
+  if (reader->case_cnt != 0 && reader->class->read (reader, reader->aux, c)) 
+    {
+      assert (case_get_value_cnt (c) == reader->value_cnt);
+      if (reader->case_cnt != CASENUMBER_MAX)
+        reader->case_cnt--;
+      return true; 
+    }
+  else 
+    {
+      reader->case_cnt = 0;
+      case_nullify (c);
+      return false; 
+    }
 }
 
-struct casereader *
-casereader_create (const struct taint *taint,
-                   size_t value_cnt, casenumber case_cnt,
-                   const struct casereader_class *class, void *aux) 
+/* Destroys READER.
+   Returns false if an I/O error was detected on READER, true
+   otherwise. */
+bool
+casereader_destroy (struct casereader *reader) 
 {
-  struct casereader *reader = xmalloc (sizeof *reader);
-  assert (class->destroy != NULL);
-  reader->taint = taint != NULL ? taint_clone (taint) : taint_create ();
-  reader->value_cnt = value_cnt;
-  reader->case_cnt = case_cnt;
-  reader->class = class;
-  reader->aux = aux;
-  return reader;
+  bool ok = true;
+  if (reader != NULL) 
+    {
+      reader->class->destroy (reader, reader->aux);
+      ok = taint_destroy (reader->taint);
+      free (reader);
+    }
+  return ok;
 }
 
+/* Returns a clone of READER.  READER and its clone may be used
+   to read the same sequence of cases in the same order, barring
+   I/O errors. */
 struct casereader *
 casereader_clone (const struct casereader *reader_) 
 {
@@ -87,17 +106,8 @@
   return clone;
 }
 
-static void
-casereader_swap (struct casereader *a, struct casereader *b) 
-{
-  if (a != b) 
-    {
-      struct casereader tmp = *a;
-      *a = *b;
-      *b = tmp;
-    }
-}
-
+/* Makes a copy of ORIGINAL into *NEW1 (if NEW1 is non-null) and
+   *NEW2 (if NEW2 is non-null), then destroys ORIGINAL. */
 void
 casereader_split (struct casereader *original,
                   struct casereader **new1, struct casereader **new2) 
@@ -115,71 +125,107 @@
     casereader_destroy (original);
 }
 
-bool
-casereader_destroy (struct casereader *reader) 
+/* Returns a copy of READER, which is itself destroyed.
+   Useful for taking over ownership of a casereader, to enforce
+   preventing the original owner from accessing the casereader
+   again. */
+struct casereader *
+casereader_rename (struct casereader *reader) 
 {
-  bool ok = true;
-  if (reader != NULL) 
-    {
-      reader->class->destroy (reader, reader->aux);
-      ok = taint_destroy (reader->taint);
+  struct casereader *new = xmemdup (reader, sizeof *reader);
       free (reader);
-    }
-  return ok;
+  return new;
 }
 
-bool
-casereader_read (struct casereader *reader, struct ccase *c) 
+/* Exchanges the casereaders referred to by A and B. */
+void
+casereader_swap (struct casereader *a, struct casereader *b) 
 {
-  if (reader->case_cnt != 0 && reader->class->read (reader, reader->aux, c)) 
-    {
-      //assert (case_get_value_cnt (c) == reader->value_cnt);
-      if (reader->case_cnt != CASENUMBER_MAX)
-        reader->case_cnt--;
-      return true; 
-    }
-  else 
+  if (a != b) 
     {
-      reader->case_cnt = 0;
-      case_nullify (c);
-      return false; 
+      struct casereader tmp = *a;
+      *a = *b;
+      *b = tmp;
     }
 }
 
+/* Creates a new case in C and reads the (IDX + 1)'th case from
+   READER into it.  The caller owns C and must destroy C when its
+   data is no longer needed.  Return true if successful, false
+   when cases have been exhausted or upon detection of an I/O
+   error.  In the latter case, C is set to the null case. */
 bool
 casereader_peek (struct casereader *reader, casenumber idx, struct ccase *c)
 {
-  if (idx >= reader->case_cnt)
-    return NULL;
+  if (idx < reader->case_cnt)
+    {
   if (reader->class->peek == NULL)
     insert_casereader_buffer (reader);
-  return reader->class->peek (reader, reader->aux, idx, c);
+      if (reader->class->peek (reader, reader->aux, idx, c))
+        return true;
+    }
+  if (reader->case_cnt > idx)
+    reader->case_cnt = idx;
+  case_nullify (c);
+  return false;
 }
 
+/* Returns true if an I/O error or another hard error has
+   occurred on READER, a clone of READER, or on some object on
+   which READER's data has a dependency, false otherwise. */
 bool
 casereader_error (const struct casereader *reader) 
 {
   return taint_is_tainted (reader->taint);
 }
 
+/* Marks READER as having encountered an error.
+
+   Ordinarily, this function should be called by the
+   implementation of a casereader, not by the casereader's
+   client.  Instead, casereader clients should usually ensure
+   that a casereader's error state is correct by using
+   taint_propagate to propagate to the casereader's taint
+   structure, which may be obtained via casereader_get_taint. */
 void
 casereader_force_error (struct casereader *reader) 
 {
   taint_set_taint (reader->taint);
 }
 
+/* Returns READER's associate taint object, for use with
+   taint_propagate and other taint functions. */
 const struct taint *
 casereader_get_taint (const struct casereader *reader) 
 {
   return reader->taint;
 }
 
+/* Returns the number of cases that will be read by successive
+   calls to casereader_read for READER, assuming that no errors
+   occur.  Upon an error condition, the case count drops to 0, so
+   that no more cases can be obtained.
+
+   Not all casereaders can predict the number of cases that they
+   will produce without actually reading all of them.  In that
+   case, this function returns CASENUMBER_MAX.  To obtain the
+   actual number of cases in such a casereader, use
+   casereader_count_cases. */
 casenumber
 casereader_get_case_cnt (struct casereader *reader) 
 {
   return reader->case_cnt;
 }
 
+/* Returns the number of cases that will be read by successive
+   calls to casereader_read for READER, assuming that no errors
+   occur.  Upon an error condition, the case count drops to 0, so
+   that no more cases can be obtained.
+
+   For a casereader that cannot predict the number of cases it
+   will produce, this function actually reads (and discards) all
+   of the contents of a clone of READER.  Thus, the return value
+   is always correct in the absence of I/O errors. */
 casenumber
 casereader_count_cases (struct casereader *reader)
 {
@@ -198,12 +244,15 @@
   return reader->case_cnt;
 }
 
+/* Returns the number of struct values in each case in READER. */
 size_t
 casereader_get_value_cnt (struct casereader *reader) 
 {
   return reader->value_cnt;
 }
 
+/* Copies all the cases in READER to WRITER, propagating errors
+   appropriately. */
 void
 casereader_transfer (struct casereader *reader, struct casewriter *writer)
 {
@@ -216,205 +265,76 @@
   casereader_destroy (reader);
 }
 
-struct casereader_filter 
-  {
-    struct casereader *subreader;
-    bool (*include) (const struct ccase *, void *aux);
-    bool (*destroy) (void *aux);
-    void *aux;
-    struct casewriter *exclude;
-  };
-
-static struct casereader_class casereader_filter_class;
-
+/* Creates and returns a new casereader.  This function is
+   intended for use by casereader implementations, not be
+   casereader clients.
+
+   Ordinarily, specify a null pointer for TAINT, in which case
+   the new casereader will have a new, unique taint object.  If
+   the new casereader should have a clone of an existing taint
+   object, specify that object as TAINT.  (This is most commonly
+   useful in an implementation of the "clone" casereader_class
+   function, in which case the cloned casereader should have the
+   same taint object as the original casereader.)
+
+   VALUE_CNT must be the number of struct values per case read
+   from the casereader.
+
+   CASE_CNT should be the number of cases that casereader_read
+   will return from the casereader in successive calls.  If the
+   number of cases cannot be predicted in advance, specify
+   CASENUMBER_MAX.
+
+   CLASS and AUX are a set of casereader implementation-specific
+   member functions and auxiliary data to pass to those member
+   functions, respectively. */
 struct casereader *
-casereader_create_filter_func (struct casereader *subreader,
-                               bool (*include) (const struct ccase *,
-                                                void *aux),
-                               bool (*destroy) (void *aux),
-                               void *aux,
-                               struct casewriter *exclude) 
-{
-  struct casereader_filter *filter = xmalloc (sizeof *filter);
-  struct casereader *reader;
-  filter->subreader = casereader_rename (subreader);
-  filter->include = include;
-  filter->destroy = destroy;
-  filter->aux = aux;
-  filter->exclude = exclude;
-  reader = casereader_create (NULL,
-                              casereader_get_value_cnt (filter->subreader),
-                              CASENUMBER_MAX,
-                              &casereader_filter_class, filter);
-  taint_propagate (casereader_get_taint (filter->subreader),
-                   casereader_get_taint (reader));
-  return reader;
-}
-
-static bool
-casereader_filter_read (struct casereader *reader UNUSED, void *filter_,
-                        struct ccase *c) 
-
-{
-  struct casereader_filter *filter = filter_;
-  for (;;)
-    {
-      if (!casereader_read (filter->subreader, c))
-        return false;
-      else if (filter->include (c, filter->aux)) 
-        return true;
-      else if (filter->exclude != NULL)
-        casewriter_write (filter->exclude, c);
-      else
-        case_destroy (c); 
-    }
-}
-
-static void
-casereader_filter_destroy (struct casereader *reader, void *filter_) 
-{
-  struct casereader_filter *filter = filter_;
-  casereader_destroy (filter->subreader);
-  if (filter->destroy != NULL && !filter->destroy (filter->aux))
-    casereader_force_error (reader);
-  free (filter);
-}
-
-static struct casereader_class casereader_filter_class = 
-  {
-    casereader_filter_read,
-    casereader_filter_destroy,
-
-    /* We could in fact delegate clone to the subreader, if the
-       filter function is required to have no memory and if we
-       added reference counting.  But it might be useful to have
-       filter functions with memory and in any case this would
-       require a little extra work. */
-    NULL,
-  };
-
-struct casereader_filter_weight 
-  {
-    const struct variable *weight_var;
-    bool *warn_on_invalid;
-    bool local_warn_on_invalid;
-  };
-
-static bool
-casereader_filter_weight_include (const struct ccase *c, void *cfw_) 
-{
-  struct casereader_filter_weight *cfw = cfw_;
-  double value = case_num (c, cfw->weight_var);
-  if (value >= 0.0 && !var_is_num_missing (cfw->weight_var, value, MV_ANY))
-    return true;
-  else
-    {
-      if (*cfw->warn_on_invalid) 
-        {
-         msg (SW, _("At least one case in the data read had a weight value "
-                    "that was user-missing, system-missing, zero, or "
-                    "negative.  These case(s) were ignored."));
-          *cfw->warn_on_invalid = false;
-        }
-      return false;
-    }
-}
-
-static bool
-casereader_filter_weight_destroy (void *cfw_) 
+casereader_create (const struct taint *taint,
+                   size_t value_cnt, casenumber case_cnt,
+                   const struct casereader_class *class, void *aux) 
 {
-  struct casereader_filter_weight *cfw = cfw_;
-  free (cfw);
-  return true;
-}
-
-struct casereader *
-casereader_create_filter_weight (struct casereader *reader,
-                                 const struct dictionary *dict,
-                                 bool *warn_on_invalid,
-                                 struct casewriter *exclude) 
-{
-  struct variable *weight_var = dict_get_weight (dict);
-  if (weight_var != NULL) 
-    {
-      struct casereader_filter_weight *cfw = xmalloc (sizeof *cfw);
-      cfw->weight_var = weight_var;
-      cfw->warn_on_invalid = (warn_on_invalid
-                               ? warn_on_invalid
-                               : &cfw->local_warn_on_invalid);
-      cfw->local_warn_on_invalid = true;
-      reader = casereader_create_filter_func (reader,
-                                              casereader_filter_weight_include,
-                                              casereader_filter_weight_destroy,
-                                              cfw, exclude);
-    }
-  else
-    reader = casereader_rename (reader);
+  struct casereader *reader = xmalloc (sizeof *reader);
+  reader->taint = taint != NULL ? taint_clone (taint) : taint_create ();
+  reader->value_cnt = value_cnt;
+  reader->case_cnt = case_cnt;
+  reader->class = class;
+  reader->aux = aux;
   return reader;
 }
 
-struct casereader_filter_missing 
-  {
-    struct variable **vars;
-    size_t var_cnt;
-    enum mv_class class;
-  };
-
-static bool
-casereader_filter_missing_include (const struct ccase *c, void *cfm_) 
-{
-  const struct casereader_filter_missing *cfm = cfm_;
-  size_t i;
-
-  for (i = 0; i < cfm->var_cnt; i++)
-    {
-      struct variable *var = cfm->vars[i];
-      const union value *value = case_data (c, var);
-      if (var_is_value_missing (var, value, cfm->class))
-        return false;
-    }
-  return true;
-}
-
-static bool
-casereader_filter_missing_destroy (void *cfm_) 
-{
-  struct casereader_filter_missing *cfm = cfm_;
-  free (cfm->vars);
-  free (cfm);
-  return true;
-}
+/* Buffered casereader.
 
-struct casereader *
-casereader_create_filter_missing (struct casereader *reader,
-                                  struct variable **vars, size_t var_cnt,
-                                  enum mv_class class,
-                                  struct casewriter *exclude) 
-{
-  if (var_cnt > 0 && class != MV_NEVER) 
-    {
-      struct casereader_filter_missing *cfm = xmalloc (sizeof *cfm);
-      cfm->vars = xmemdup (vars, sizeof *vars * var_cnt);
-      cfm->var_cnt = var_cnt;
-      cfm->class = class;
-      return casereader_create_filter_func (reader,
-                                            casereader_filter_missing_include,
-                                            casereader_filter_missing_destroy,
-                                            cfm,
-                                            exclude);
-    }
-  else
-    return casereader_rename (reader);
-}
+   The "clone" and "peek" operations aren't implemented by all
+   types of casereaders, but we have to expose a uniform
+   interface anyhow.  We do this by interposing a buffering
+   casereader on top of the existing casereader on the first call
+   to "clone" or "peek".  The buffering casereader maintains a
+   window of cases that spans the positions of the original
+   casereader and all of its clones (the "clone set"), from the
+   position of the casereader that has read the fewest cases to
+   the position of the casereader that has read the most.  
+
+   Thus, if all of the casereaders in the clone set are at
+   approximately the same position, only a few cases are buffered
+   and there is little inefficiency.  If, on the other hand, one
+   casereader is not used to read any cases at all, but another
+   one is used to read all of the cases, the entire contents of
+   the casereader is copied into the buffer.  This still might
+   not be so inefficient, given that case data in memory is
+   shared across multiple identical copies, but in the worst case
+   the window implementation will write cases to disk instead of
+   maintaining them in-memory. */
 
+/* A buffered casereader. */
 struct casereader_buffer 
   {
-    struct casewindow *window;
-    struct casereader *subreader;
+    struct casewindow *window;          /* Window of buffered cases. */
+    struct casereader *subreader;       /* Subordinate casereader. */
   };
 
 static struct buffered_reader_class casereader_buffer_class;
 
+/* Interposes a buffered casereader atop of READER. */
 static void
 insert_casereader_buffer (struct casereader *reader) 
 {
@@ -425,14 +345,15 @@
   b->subreader = buffered_reader_create (NULL, value_cnt, case_cnt,
                                          &casereader_buffer_class, b);
   casereader_swap (reader, b->subreader);
-  /* Should we do these propagations or should we clone one of
-     them and pass it to buffered_reader_create? */
   taint_propagate (casewindow_get_taint (b->window),
                    casereader_get_taint (reader));
   taint_propagate (casereader_get_taint (b->subreader),
                    casereader_get_taint (reader));
 }
 
+/* Ensures that B's window contains at least CASE_CNT cases.
+   Return true if successful, false upon reaching the end of B's
+   subreader or an I/O error. */
 static bool
 prime_casereader_buffer (struct casereader_buffer *b, casenumber case_cnt) 
 {
@@ -446,6 +367,9 @@
   return true;
 }
 
+/* Reads the case at the given 0-based OFFSET from the front of
+   the window into C.  Returns true if successful, false if
+   OFFSET is beyond the end of file or upon I/O error. */
 static bool
 casereader_buffer_read (void *b_, casenumber offset, struct ccase *c) 
 {
@@ -454,6 +378,7 @@
           && casewindow_get_case (b->window, offset, c));
 }
 
+/* Destroys B. */
 static void
 casereader_buffer_destroy (void *b_) 
 {
@@ -463,6 +388,7 @@
   free (b);
 }
 
+/* Discards CNT cases from the front of B's window. */
 static void
 casereader_buffer_advance (void *b_, casenumber cnt)
 {
@@ -470,92 +396,10 @@
   casewindow_pop_tail (b->window, cnt);
 }
 
+/* Class for the buffered reader. */
 static struct buffered_reader_class casereader_buffer_class = 
   {
     casereader_buffer_read,
     casereader_buffer_destroy,
     casereader_buffer_advance,
   };
-
-static bool
-casereader_counter_include (const struct ccase *c UNUSED, void *counter_) 
-{
-  casenumber *counter = counter_;
-  ++*counter;
-  return true;
-}
-
-struct casereader *
-casereader_create_counter (struct casereader *reader, casenumber *counter,
-                           casenumber initial_value) 
-{
-  *counter = initial_value;
-  return casereader_create_filter_func (reader, casereader_counter_include,
-                                        NULL, counter, NULL);
-}
-
-struct casereader_translator
-  {
-    struct casereader *subreader;
-
-    void (*translate) (const struct ccase *input, struct ccase *output,
-                       void *aux);
-    bool (*destroy) (void *aux);
-    void *aux;
-  };
-
-static struct casereader_class casereader_translator_class;
-
-struct casereader *
-casereader_create_translator (struct casereader *subreader,
-                              size_t output_value_cnt,
-                              void (*translate) (const struct ccase *input,
-                                                 struct ccase *output,
-                                                 void *aux),
-                              bool (*destroy) (void *aux),
-                              void *aux) 
-{
-  struct casereader_translator *ct = xmalloc (sizeof *ct);
-  struct casereader *reader;
-  ct->subreader = casereader_rename (subreader);
-  ct->translate = translate;
-  ct->destroy = destroy;
-  ct->aux = aux;
-  reader = casereader_create (NULL, output_value_cnt,
-                              casereader_get_case_cnt (ct->subreader),
-                              &casereader_translator_class, ct);
-  taint_propagate (casereader_get_taint (ct->subreader),
-                   casereader_get_taint (reader));
-  return reader;
-}
-
-static bool
-casereader_translator_read (struct casereader *reader UNUSED,
-                            void *ct_, struct ccase *c) 
-{
-  struct casereader_translator *ct = ct_;
-  struct ccase tmp;
-
-  if (casereader_read (ct->subreader, &tmp)) 
-    {
-      ct->translate (&tmp, c, ct->aux);
-      return true; 
-    }
-  else
-    return false;
-}
-
-static void
-casereader_translator_destroy (struct casereader *reader UNUSED, void *ct_) 
-{
-  struct casereader_translator *ct = ct_;
-  casereader_destroy (ct->subreader);
-  ct->destroy (ct->aux);
-  free (ct);
-}
-
-static struct casereader_class casereader_translator_class = 
-  {
-    casereader_translator_read,
-    casereader_translator_destroy,
-  };

Index: data/case-tmpfile.h
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/Attic/case-tmpfile.h,v
retrieving revision 1.1.2.2
retrieving revision 1.1.2.3
diff -u -b -r1.1.2.2 -r1.1.2.3
--- data/case-tmpfile.h 14 Apr 2007 05:04:23 -0000      1.1.2.2
+++ data/case-tmpfile.h 6 May 2007 22:48:27 -0000       1.1.2.3
@@ -23,7 +23,10 @@
 
 struct case_tmpfile *case_tmpfile_create (size_t value_cnt);
 bool case_tmpfile_destroy (struct case_tmpfile *);
+
 bool case_tmpfile_error (const struct case_tmpfile *);
+void case_tmpfile_force_error (struct case_tmpfile *);
+const struct taint *case_tmpfile_get_taint (const struct case_tmpfile *);
 
 bool case_tmpfile_get_values (const struct case_tmpfile *,
                               casenumber, size_t start_value,

Index: data/case-tmpfile.c
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/Attic/case-tmpfile.c,v
retrieving revision 1.1.2.4
retrieving revision 1.1.2.5
diff -u -b -r1.1.2.4 -r1.1.2.5
--- data/case-tmpfile.c 5 May 2007 21:55:48 -0000       1.1.2.4
+++ data/case-tmpfile.c 6 May 2007 22:48:27 -0000       1.1.2.5
@@ -25,6 +25,7 @@
 #include <stdlib.h>
 
 #include <libpspp/assertion.h>
+#include <libpspp/taint.h>
 
 #include "error.h"
 #include "xalloc.h"
@@ -42,6 +43,7 @@
 
 struct case_tmpfile 
   {
+    struct taint *taint;
     FILE *file;
     size_t value_cnt;
     off_t position;
@@ -51,9 +53,13 @@
 case_tmpfile_create (size_t value_cnt) 
 {
   struct case_tmpfile *ctf = xmalloc (sizeof *ctf);
+  ctf->taint = taint_create ();
   ctf->file = tmpfile ();
   if (ctf->file == NULL)
+    {
     error (0, errno, _("failed to create temporary file"));
+      taint_set_taint (ctf->taint);
+    }
   ctf->value_cnt = value_cnt;
   ctf->position = 0;
   return ctf;
@@ -62,33 +68,34 @@
 bool
 case_tmpfile_destroy (struct case_tmpfile *ctf) 
 {
+  bool ok = true;
   if (ctf != NULL) 
     {
-      bool ok = !case_tmpfile_error (ctf);
+      struct taint *taint = ctf->taint;
       if (ctf->file != NULL)
         fclose (ctf->file);
       free (ctf);
-      return ok;
+      ok = taint_destroy (taint);
     }
-  else
-    return true; 
+  return ok;
 }
 
 bool
 case_tmpfile_error (const struct case_tmpfile *ctf) 
 {
-  return ctf->file == NULL;
+  return taint_is_tainted (ctf->taint);
 }
 
-static void
-mark_error (const struct case_tmpfile *ctf_) 
+void
+case_tmpfile_force_error (struct case_tmpfile *ctf) 
 {
-  struct case_tmpfile *ctf = (struct case_tmpfile *) ctf_;
-  if (ctf->file != NULL) 
-    {
-      fclose (ctf->file);
-      ctf->file = NULL;
-    }
+  taint_set_taint (ctf->taint);
+}
+
+const struct taint *
+case_tmpfile_get_taint (const struct case_tmpfile *ctf) 
+{
+  return ctf->taint;
 }
 
 static bool
@@ -112,7 +119,7 @@
       else
         {
           error (0, errno, _("seeking in temporary file"));
-          mark_error (ctf); 
+          case_tmpfile_force_error (ctf);
         }
     }
 
@@ -127,7 +134,7 @@
   assert (!case_tmpfile_error (ctf));
   if (fread (buffer, bytes, 1, ctf->file) != 1)
     {
-      mark_error (ctf);
+      case_tmpfile_force_error (ctf);
       if (ferror (ctf->file))
         error (0, errno, _("reading temporary file"));
       else if (feof (ctf->file))
@@ -146,7 +153,7 @@
   assert (!case_tmpfile_error (ctf));
   if (fwrite (buffer, bytes, 1, ctf->file) != 1)
     {
-      mark_error (ctf); 
+      case_tmpfile_force_error (ctf); 
       error (0, errno, _("writing to temporary file"));
       return false;
     }

Index: data/automake.mk
===================================================================
RCS file: /cvsroot/pspp/pspp/src/data/automake.mk,v
retrieving revision 1.15.2.2
retrieving revision 1.15.2.3
diff -u -b -r1.15.2.2 -r1.15.2.3
--- data/automake.mk    14 Apr 2007 05:04:23 -0000      1.15.2.2
+++ data/automake.mk    6 May 2007 22:48:27 -0000       1.15.2.3
@@ -18,6 +18,8 @@
        src/data/caseinit.c \
        src/data/caseinit.h \
        src/data/casereader.c \
+       src/data/casereader-filter.c \
+       src/data/casereader-translator.c \
        src/data/casereader.h \
        src/data/casereader-private.h \
        src/data/case-tmpfile.c \

Index: data/casereader-translator.c
===================================================================
RCS file: data/casereader-translator.c
diff -N data/casereader-translator.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ data/casereader-translator.c        6 May 2007 22:48:27 -0000       1.1.2.1
@@ -0,0 +1,94 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 2007 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA. */
+
+#include <config.h>
+
+#include <data/casereader.h>
+
+#include <stdlib.h>
+
+#include <data/casereader-private.h>
+#include <libpspp/taint.h>
+
+#include "xalloc.h"
+
+struct casereader_translator
+  {
+    struct casereader *subreader;
+
+    void (*translate) (const struct ccase *input, struct ccase *output,
+                       void *aux);
+    bool (*destroy) (void *aux);
+    void *aux;
+  };
+
+static struct casereader_class casereader_translator_class;
+
+struct casereader *
+casereader_create_translator (struct casereader *subreader,
+                              size_t output_value_cnt,
+                              void (*translate) (const struct ccase *input,
+                                                 struct ccase *output,
+                                                 void *aux),
+                              bool (*destroy) (void *aux),
+                              void *aux) 
+{
+  struct casereader_translator *ct = xmalloc (sizeof *ct);
+  struct casereader *reader;
+  ct->subreader = casereader_rename (subreader);
+  ct->translate = translate;
+  ct->destroy = destroy;
+  ct->aux = aux;
+  reader = casereader_create (NULL, output_value_cnt,
+                              casereader_get_case_cnt (ct->subreader),
+                              &casereader_translator_class, ct);
+  taint_propagate (casereader_get_taint (ct->subreader),
+                   casereader_get_taint (reader));
+  return reader;
+}
+
+static bool
+casereader_translator_read (struct casereader *reader UNUSED,
+                            void *ct_, struct ccase *c) 
+{
+  struct casereader_translator *ct = ct_;
+  struct ccase tmp;
+
+  if (casereader_read (ct->subreader, &tmp)) 
+    {
+      ct->translate (&tmp, c, ct->aux);
+      return true; 
+    }
+  else
+    return false;
+}
+
+static void
+casereader_translator_destroy (struct casereader *reader UNUSED, void *ct_) 
+{
+  struct casereader_translator *ct = ct_;
+  casereader_destroy (ct->subreader);
+  ct->destroy (ct->aux);
+  free (ct);
+}
+
+static struct casereader_class casereader_translator_class = 
+  {
+    casereader_translator_read,
+    casereader_translator_destroy,
+  };

Index: data/casereader-filter.c
===================================================================
RCS file: data/casereader-filter.c
diff -N data/casereader-filter.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ data/casereader-filter.c    6 May 2007 22:48:27 -0000       1.1.2.1
@@ -0,0 +1,244 @@
+/* PSPP - computes sample statistics.
+   Copyright (C) 2007 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA. */
+
+#include <config.h>
+
+#include <data/casereader.h>
+
+#include <stdlib.h>
+
+#include <data/casereader-private.h>
+#include <data/casewriter.h>
+#include <data/variable.h>
+#include <data/dictionary.h>
+#include <libpspp/taint.h>
+#include <libpspp/message.h>
+
+#include "xalloc.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+struct casereader_filter 
+  {
+    struct casereader *subreader;
+    bool (*include) (const struct ccase *, void *aux);
+    bool (*destroy) (void *aux);
+    void *aux;
+    struct casewriter *exclude;
+  };
+
+static struct casereader_class casereader_filter_class;
+
+struct casereader *
+casereader_create_filter_func (struct casereader *subreader,
+                               bool (*include) (const struct ccase *,
+                                                void *aux),
+                               bool (*destroy) (void *aux),
+                               void *aux,
+                               struct casewriter *exclude) 
+{
+  struct casereader_filter *filter = xmalloc (sizeof *filter);
+  struct casereader *reader;
+  filter->subreader = casereader_rename (subreader);
+  filter->include = include;
+  filter->destroy = destroy;
+  filter->aux = aux;
+  filter->exclude = exclude;
+  reader = casereader_create (NULL,
+                              casereader_get_value_cnt (filter->subreader),
+                              CASENUMBER_MAX,
+                              &casereader_filter_class, filter);
+  taint_propagate (casereader_get_taint (filter->subreader),
+                   casereader_get_taint (reader));
+  return reader;
+}
+
+static bool
+casereader_filter_read (struct casereader *reader UNUSED, void *filter_,
+                        struct ccase *c) 
+
+{
+  struct casereader_filter *filter = filter_;
+  for (;;)
+    {
+      if (!casereader_read (filter->subreader, c))
+        return false;
+      else if (filter->include (c, filter->aux)) 
+        return true;
+      else if (filter->exclude != NULL)
+        casewriter_write (filter->exclude, c);
+      else
+        case_destroy (c); 
+    }
+}
+
+static void
+casereader_filter_destroy (struct casereader *reader, void *filter_) 
+{
+  struct casereader_filter *filter = filter_;
+  casereader_destroy (filter->subreader);
+  if (filter->destroy != NULL && !filter->destroy (filter->aux))
+    casereader_force_error (reader);
+  free (filter);
+}
+
+static struct casereader_class casereader_filter_class = 
+  {
+    casereader_filter_read,
+    casereader_filter_destroy,
+
+    /* We could in fact delegate clone to the subreader, if the
+       filter function is required to have no memory and if we
+       added reference counting.  But it might be useful to have
+       filter functions with memory and in any case this would
+       require a little extra work. */
+    NULL,
+  };
+
+struct casereader_filter_weight 
+  {
+    const struct variable *weight_var;
+    bool *warn_on_invalid;
+    bool local_warn_on_invalid;
+  };
+
+static bool
+casereader_filter_weight_include (const struct ccase *c, void *cfw_) 
+{
+  struct casereader_filter_weight *cfw = cfw_;
+  double value = case_num (c, cfw->weight_var);
+  if (value >= 0.0 && !var_is_num_missing (cfw->weight_var, value, MV_ANY))
+    return true;
+  else
+    {
+      if (*cfw->warn_on_invalid) 
+        {
+         msg (SW, _("At least one case in the data read had a weight value "
+                    "that was user-missing, system-missing, zero, or "
+                    "negative.  These case(s) were ignored."));
+          *cfw->warn_on_invalid = false;
+        }
+      return false;
+    }
+}
+
+static bool
+casereader_filter_weight_destroy (void *cfw_) 
+{
+  struct casereader_filter_weight *cfw = cfw_;
+  free (cfw);
+  return true;
+}
+
+struct casereader *
+casereader_create_filter_weight (struct casereader *reader,
+                                 const struct dictionary *dict,
+                                 bool *warn_on_invalid,
+                                 struct casewriter *exclude) 
+{
+  struct variable *weight_var = dict_get_weight (dict);
+  if (weight_var != NULL) 
+    {
+      struct casereader_filter_weight *cfw = xmalloc (sizeof *cfw);
+      cfw->weight_var = weight_var;
+      cfw->warn_on_invalid = (warn_on_invalid
+                               ? warn_on_invalid
+                               : &cfw->local_warn_on_invalid);
+      cfw->local_warn_on_invalid = true;
+      reader = casereader_create_filter_func (reader,
+                                              casereader_filter_weight_include,
+                                              casereader_filter_weight_destroy,
+                                              cfw, exclude);
+    }
+  else
+    reader = casereader_rename (reader);
+  return reader;
+}
+
+struct casereader_filter_missing 
+  {
+    struct variable **vars;
+    size_t var_cnt;
+    enum mv_class class;
+  };
+
+static bool
+casereader_filter_missing_include (const struct ccase *c, void *cfm_) 
+{
+  const struct casereader_filter_missing *cfm = cfm_;
+  size_t i;
+
+  for (i = 0; i < cfm->var_cnt; i++)
+    {
+      struct variable *var = cfm->vars[i];
+      const union value *value = case_data (c, var);
+      if (var_is_value_missing (var, value, cfm->class))
+        return false;
+    }
+  return true;
+}
+
+static bool
+casereader_filter_missing_destroy (void *cfm_) 
+{
+  struct casereader_filter_missing *cfm = cfm_;
+  free (cfm->vars);
+  free (cfm);
+  return true;
+}
+
+struct casereader *
+casereader_create_filter_missing (struct casereader *reader,
+                                  struct variable **vars, size_t var_cnt,
+                                  enum mv_class class,
+                                  struct casewriter *exclude) 
+{
+  if (var_cnt > 0 && class != MV_NEVER) 
+    {
+      struct casereader_filter_missing *cfm = xmalloc (sizeof *cfm);
+      cfm->vars = xmemdup (vars, sizeof *vars * var_cnt);
+      cfm->var_cnt = var_cnt;
+      cfm->class = class;
+      return casereader_create_filter_func (reader,
+                                            casereader_filter_missing_include,
+                                            casereader_filter_missing_destroy,
+                                            cfm,
+                                            exclude);
+    }
+  else
+    return casereader_rename (reader);
+}
+
+
+static bool
+casereader_counter_include (const struct ccase *c UNUSED, void *counter_) 
+{
+  casenumber *counter = counter_;
+  ++*counter;
+  return true;
+}
+
+struct casereader *
+casereader_create_counter (struct casereader *reader, casenumber *counter,
+                           casenumber initial_value) 
+{
+  *counter = initial_value;
+  return casereader_create_filter_func (reader, casereader_counter_include,
+                                        NULL, counter, NULL);
+}




reply via email to

[Prev in Thread] Current Thread [Next in Thread]