Add datasheet.
[pspp-builds.git] / src / data / storage-stream.c
index a758c5a1e021e66051778b320203c186b5c21805..4ff939cd02a1559ebdcaafeb8b51738ffc9a8973 100644 (file)
@@ -1,6 +1,5 @@
 /* PSPP - computes sample statistics.
    Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
-   Written by Ben Pfaff <blp@gnu.org>.
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
 
 #include <data/storage-stream.h>
 
+#include <assert.h>
 #include <stdlib.h>
 
 #include <data/case-sink.h>
 #include <data/case-source.h>
 #include <data/case.h>
 #include <data/casefile.h> 
+#include <data/casefile-factory.h>
 
 #include "xalloc.h"
 
-/* Information about storage sink or source. */
-struct storage_stream_info 
+/* Storage sink. */
+
+/* Information about storage sink. */
+struct storage_sink_info 
   {
     struct casefile *casefile;  /* Storage. */
   };
-\f
-/* Storage sink. */
+
+static struct storage_sink_info *
+get_storage_sink_info (struct case_sink *sink) 
+{
+  assert (sink->class == &storage_sink_class);
+  return sink->aux;
+}
 
 /* Initializes a storage sink. */
 static void
 storage_sink_open (struct case_sink *sink)
 {
-  struct storage_stream_info *info;
+  struct storage_sink_info *info;
 
   sink->aux = info = xmalloc (sizeof *info);
-  info->casefile = casefile_create (sink->value_cnt);
-}
-
-/* Destroys storage stream represented by INFO. */
-static void
-destroy_storage_stream_info (struct storage_stream_info *info) 
-{
-  if (info != NULL) 
-    {
-      casefile_destroy (info->casefile);
-      free (info); 
-    }
+  info->casefile = sink->factory->create_casefile (sink->factory,
+                                                  sink->value_cnt);
 }
 
 /* Writes case C to the storage sink SINK.
@@ -64,8 +62,7 @@ destroy_storage_stream_info (struct storage_stream_info *info)
 static bool
 storage_sink_write (struct case_sink *sink, const struct ccase *c)
 {
-  struct storage_stream_info *info = sink->aux;
-
+  struct storage_sink_info *info = get_storage_sink_info (sink);
   return casefile_append (info->casefile, c);
 }
 
@@ -73,7 +70,9 @@ storage_sink_write (struct case_sink *sink, const struct ccase *c)
 static void
 storage_sink_destroy (struct case_sink *sink)
 {
-  destroy_storage_stream_info (sink->aux);
+  struct storage_sink_info *info = get_storage_sink_info (sink);
+  casefile_destroy (info->casefile);
+  free (info); 
 }
 
 /* Closes the sink and returns a storage source to read back the
@@ -81,9 +80,9 @@ storage_sink_destroy (struct case_sink *sink)
 static struct case_source *
 storage_sink_make_source (struct case_sink *sink) 
 {
-  struct case_source *source
-    = create_case_source (&storage_source_class, sink->aux);
-  sink->aux = NULL;
+  struct storage_sink_info *info = get_storage_sink_info (sink);
+  struct case_source *source = storage_source_create (info->casefile);
+  info->casefile = NULL;
   return source;
 }
 
@@ -99,74 +98,108 @@ const struct case_sink_class storage_sink_class =
 \f
 /* Storage source. */
 
+struct storage_source_info 
+  {
+    struct casefile *casefile;  /* Storage. */
+    struct casereader *reader;  /* Reader. */
+  };
+
+static struct storage_source_info *
+get_storage_source_info (const struct case_source *source) 
+{
+  assert (source->class == &storage_source_class);
+  return source->aux;
+}
+
 /* Returns the number of cases that will be read by
    storage_source_read(). */
 static int
 storage_source_count (const struct case_source *source) 
 {
-  struct storage_stream_info *info = source->aux;
-
+  struct storage_source_info *info = get_storage_source_info (source);
   return casefile_get_case_cnt (info->casefile);
 }
 
-/* Reads all cases from the storage source and passes them one by one to
-   write_case(). */
+/* Reads one case into OUTPUT_CASE.
+   Returns true if successful, false at end of file or if an
+   I/O error occurred. */
 static bool
-storage_source_read (struct case_source *source,
-                     struct ccase *output_case,
-                     write_case_func *write_case, write_case_data wc_data)
+storage_source_read (struct case_source *source, struct ccase *output_case)
 {
-  struct storage_stream_info *info = source->aux;
+  struct storage_source_info *info = get_storage_source_info (source);
   struct ccase casefile_case;
-  struct casereader *reader;
-  bool ok = true;
 
-  for (reader = casefile_get_reader (info->casefile);
-       ok && casereader_read (reader, &casefile_case);
-       case_destroy (&casefile_case))
+  if (info->reader == NULL)
+    info->reader = casefile_get_reader (info->casefile, NULL);
+
+  if (casereader_read (info->reader, &casefile_case))
     {
       case_copy (output_case, 0,
                  &casefile_case, 0,
                  casefile_get_value_cnt (info->casefile));
-      ok = write_case (wc_data);
+      return true;
     }
-  casereader_destroy (reader);
-
-  return ok;
+  else
+    return false;
 }
 
-/* Destroys the source's internal data. */
-static void
+/* Destroys the source.
+   Returns true if successful read, false if an I/O occurred
+   during destruction or previously. */
+static bool
 storage_source_destroy (struct case_source *source)
 {
-  destroy_storage_stream_info (source->aux);
+  struct storage_source_info *info = get_storage_source_info (source);
+  bool ok = true;
+  if (info->casefile)
+    {
+      ok = !casefile_error (info->casefile);
+      casefile_destroy (info->casefile); 
+    }
+  free (info);
+  return ok;
 }
 
-/* Storage source. */
-const struct case_source_class storage_source_class = 
-  {
-    "storage",
-    storage_source_count,
-    storage_source_read,
-    storage_source_destroy,
-  };
-
+/* Returns the casefile encapsulated by SOURCE. */
 struct casefile *
 storage_source_get_casefile (struct case_source *source) 
 {
-  struct storage_stream_info *info = source->aux;
-
-  assert (source->class == &storage_source_class);
+  struct storage_source_info *info = get_storage_source_info (source);
   return info->casefile;
 }
 
+/* Destroys SOURCE and returns the casefile that it
+   encapsulated. */
+struct casefile *
+storage_source_decapsulate (struct case_source *source) 
+{
+  struct storage_source_info *info = get_storage_source_info (source);
+  struct casefile *casefile = info->casefile;
+  assert (info->reader == NULL);
+  info->casefile = NULL;
+  free_case_source (source);
+  return casefile;
+}
+
+/* Creates and returns a new storage source that encapsulates
+   CASEFILE. */
 struct case_source *
-storage_source_create (struct casefile *cf)
+storage_source_create (struct casefile *casefile)
 {
-  struct storage_stream_info *info;
+  struct storage_source_info *info;
 
   info = xmalloc (sizeof *info);
-  info->casefile = cf;
+  info->casefile = casefile;
+  info->reader = NULL;
 
   return create_case_source (&storage_source_class, info);
 }
+
+/* Storage source. */
+const struct case_source_class storage_source_class = 
+  {
+    "storage",
+    storage_source_count,
+    storage_source_read,
+    storage_source_destroy,
+  };