casereader: Make parameter to casereader_count_cases const.
[pspp-builds.git] / src / data / casereader.c
index 0eb3baf5c1ea1af841915c0b01a29a06403fe444..97b7ceff3d1b7eb19e8ac6243aef08eb961a0f6b 100644 (file)
@@ -258,19 +258,14 @@ casereader_get_case_cnt (struct casereader *reader)
 }
 
 static casenumber
-casereader_count_cases__ (struct casereader *reader, casenumber max_cases)
+casereader_count_cases__ (const struct casereader *reader,
+                          casenumber max_cases)
 {
   struct casereader *clone;
   casenumber n_cases;
 
   clone = casereader_clone (reader);
-  for (n_cases = 0; n_cases < max_cases; n_cases++)
-    {
-      struct ccase *c = casereader_read (clone);
-      if (c == NULL)
-        break;
-      case_unref (c);
-    }
+  n_cases = casereader_advance (clone, max_cases);
   casereader_destroy (clone);
 
   return n_cases;
@@ -286,10 +281,13 @@ casereader_count_cases__ (struct casereader *reader, casenumber max_cases)
    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)
+casereader_count_cases (const struct casereader *reader)
 {
   if (reader->case_cnt == CASENUMBER_MAX)
-    reader->case_cnt = casereader_count_cases__ (reader, CASENUMBER_MAX);
+    {
+      struct casereader *reader_rw = CONST_CAST (struct casereader *, reader);
+      reader_rw->case_cnt = casereader_count_cases__ (reader, CASENUMBER_MAX);
+    }
   return reader->case_cnt;
 }
 
@@ -315,6 +313,26 @@ casereader_get_proto (const struct casereader *reader)
   return reader->proto;
 }
 
+/* Skips past N cases in READER, stopping when the last case in
+   READER has been read or on an input error.  Returns the number
+   of cases successfully skipped. */
+casenumber
+casereader_advance (struct casereader *reader, casenumber n)
+{
+  casenumber i;
+
+  for (i = 0; i < n; i++)
+    {
+      struct ccase *c = casereader_read (reader);
+      if (c == NULL)
+        break;
+      case_unref (c);
+    }
+
+  return i;
+}
+
+
 /* Copies all the cases in READER to WRITER, propagating errors
    appropriately. */
 void
@@ -685,3 +703,42 @@ static const struct casereader_random_class shim_class =
     shim_destroy,
     shim_advance,
   };
+\f
+static const struct casereader_class casereader_null_class;
+
+/* Returns a casereader with no cases.  The casereader has the prototype
+   specified by PROTO.  PROTO may be specified as a null pointer, in which case
+   the casereader has no variables. */
+struct casereader *
+casereader_create_empty (const struct caseproto *proto_)
+{
+  struct casereader *reader;
+  struct caseproto *proto;
+
+  proto = proto_ != NULL ? caseproto_ref (proto_) : caseproto_create ();
+  reader = casereader_create_sequential (NULL, proto, 0,
+                                         &casereader_null_class, NULL);
+  caseproto_unref (proto);
+
+  return reader;
+}
+
+static struct ccase *
+casereader_null_read (struct casereader *reader UNUSED, void *aux UNUSED)
+{
+  return NULL;
+}
+
+static void
+casereader_null_destroy (struct casereader *reader UNUSED, void *aux UNUSED)
+{
+  /* Nothing to do. */
+}
+
+static const struct casereader_class casereader_null_class =
+  {
+    casereader_null_read,
+    casereader_null_destroy,
+    NULL,                       /* clone */
+    NULL,                       /* peek */
+  };