Change terminology from "active file" to "active dataset".
[pspp-builds.git] / src / data / dataset.c
index a94fba2c22919c0dfc29ee9746a3a2ab7a25c49a..5d0598e3a6949444c65acfd9b7d71861a7987941 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011 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
@@ -60,11 +60,6 @@ struct dataset {
   struct trns_chain *temporary_trns_chain;
   struct dictionary *dict;
 
-  /* Callback which occurs whenever the transformation chain(s) have
-     been modified */
-  transformation_change_callback_func *xform_callback;
-  void *xform_callback_aux;
-
   /* If true, cases are discarded instead of being written to
      sink. */
   bool discard_output;
@@ -98,13 +93,16 @@ struct dataset {
   bool ok;                      /* Error status. */
   struct casereader_shim *shim; /* Shim on proc_open() casereader. */
 
-  void (*callback) (void *); /* Callback for when the dataset changes */
+  const struct dataset_callbacks *callbacks;
   void *cb_data;
 
   /* Default encoding for reading syntax files. */
   char *syntax_encoding;
-}; /* struct dataset */
+};
 
+static void dataset_changed__ (struct dataset *);
+static void dataset_transformations_changed__ (struct dataset *,
+                                               bool non_empty);
 
 static void add_case_limit_trns (struct dataset *ds);
 static void add_filter_trns (struct dataset *ds);
@@ -112,18 +110,132 @@ static void add_filter_trns (struct dataset *ds);
 static void update_last_proc_invocation (struct dataset *ds);
 
 static void
-dataset_set_unsaved (const struct dataset *ds)
+dict_callback (struct dictionary *d UNUSED, void *ds_)
 {
-  if (ds->callback) ds->callback (ds->cb_data);
+  struct dataset *ds = ds_;
+  dataset_changed__ (ds);
 }
-
 \f
-/* Public functions. */
+/* Creates and returns a new dataset.  The dataset initially has an empty
+   dictionary and no data source. */
+struct dataset *
+dataset_create (void)
+{
+  struct dataset *ds;
 
+  ds = xzalloc (sizeof *ds);
+  ds->dict = dict_create ();
+  dict_set_change_callback (ds->dict, dict_callback, ds);
+  dict_set_encoding (ds->dict, get_default_encoding ());
+
+  ds->caseinit = caseinit_create ();
+  proc_cancel_all_transformations (ds);
+  ds->syntax_encoding = xstrdup ("Auto");
+  return ds;
+}
+
+/* Destroys DS. */
+void
+dataset_destroy (struct dataset *ds)
+{
+  if (ds != NULL)
+    {
+      dataset_clear (ds);
+      dict_destroy (ds->dict);
+      caseinit_destroy (ds->caseinit);
+      trns_chain_destroy (ds->permanent_trns_chain);
+      dataset_transformations_changed__ (ds, false);
+      free (ds->syntax_encoding);
+      free (ds);
+    }
+}
+
+/* Discards the active dataset's dictionary, data, and transformations. */
 void
-dataset_set_callback (struct dataset *ds, void (*cb) (void *), void *cb_data)
+dataset_clear (struct dataset *ds)
 {
-  ds->callback = cb;
+  assert (ds->proc_state == PROC_COMMITTED);
+
+  dict_clear (ds->dict);
+  fh_set_default_handle (NULL);
+
+  ds->n_lag = 0;
+
+  casereader_destroy (ds->source);
+  ds->source = NULL;
+
+  proc_cancel_all_transformations (ds);
+}
+
+/* Returns the dictionary within DS.  This is always nonnull, although it
+   might not contain any variables. */
+struct dictionary *
+dataset_dict (const struct dataset *ds)
+{
+  return ds->dict;
+}
+
+/* Replaces DS's dictionary by DICT, discarding any source and
+   transformations. */
+void
+dataset_set_dict (struct dataset *ds, struct dictionary *dict)
+{
+  assert (ds->proc_state == PROC_COMMITTED);
+  assert (ds->dict != dict);
+
+  dataset_clear (ds);
+
+  dict_destroy (ds->dict);
+  ds->dict = dict;
+  dict_set_change_callback (ds->dict, dict_callback, ds);
+}
+
+/* Returns the casereader that will be read when a procedure is executed on
+   DS.  This can be NULL if none has been set up yet. */
+const struct casereader *
+dataset_source (const struct dataset *ds)
+{
+  return ds->source;
+}
+
+/* Returns true if DS has a data source, false otherwise. */
+bool
+dataset_has_source (const struct dataset *ds)
+{
+  return dataset_source (ds) != NULL;
+}
+
+/* Replaces the active dataset's data by READER.  READER's cases must have an
+   appropriate format for DS's dictionary. */
+bool
+dataset_set_source (struct dataset *ds, struct casereader *reader)
+{
+  casereader_destroy (ds->source);
+  ds->source = reader;
+
+  caseinit_clear (ds->caseinit);
+  caseinit_mark_as_preinited (ds->caseinit, ds->dict);
+
+  return reader == NULL || !casereader_error (reader);
+}
+
+/* Returns the data source from DS and removes it from DS.  Returns a null
+   pointer if DS has no data source. */
+struct casereader *
+dataset_steal_source (struct dataset *ds)
+{
+  struct casereader *reader = ds->source;
+  ds->source = NULL;
+
+  return reader;
+}
+
+void
+dataset_set_callbacks (struct dataset *ds,
+                       const struct dataset_callbacks *callbacks,
+                       void *cb_data)
+{
+  ds->callbacks = callbacks;
   ds->cb_data = cb_data;
 }
 
@@ -139,7 +251,7 @@ dataset_get_default_syntax_encoding (const struct dataset *ds)
 {
   return ds->syntax_encoding;
 }
-
+\f
 /* Returns the last time the data was read. */
 time_t
 time_of_last_procedure (struct dataset *ds)
@@ -314,7 +426,7 @@ proc_casereader_read (struct casereader *reader UNUSED, void *ds_)
           ds->lag_cases[deque_push_front (&ds->lag)] = case_ref (c);
         }
 
-      /* Write case to replacement active file. */
+      /* Write case to replacement dataset. */
       ds->cases_written++;
       if (ds->sink != NULL)
         casewriter_write (ds->sink,
@@ -347,20 +459,20 @@ proc_casereader_destroy (struct casereader *reader, void *ds_)
 
   /* Make sure transformations happen for every input case, in
      case they have side effects, and ensure that the replacement
-     active file gets all the cases it should. */
+     active dataset gets all the cases it should. */
   while ((c = casereader_read (reader)) != NULL)
     case_unref (c);
 
   ds->proc_state = PROC_CLOSED;
   ds->ok = casereader_destroy (ds->source) && ds->ok;
   ds->source = NULL;
-  proc_set_active_file_data (ds, NULL);
+  dataset_set_source (ds, NULL);
 }
 
 /* Must return false if the source casereader, a transformation,
    or the sink casewriter signaled an error.  (If a temporary
    transformation signals an error, then the return value is
-   false, but the replacement active file may still be
+   false, but the replacement active dataset may still be
    untainted.) */
 bool
 proc_commit (struct dataset *ds)
@@ -371,7 +483,7 @@ proc_commit (struct dataset *ds)
   assert (ds->proc_state == PROC_CLOSED);
   ds->proc_state = PROC_COMMITTED;
 
-  dataset_set_unsaved (ds);
+  dataset_changed__ (ds);
 
   /* Free memory for lagged cases. */
   while (!deque_is_empty (&ds->lag))
@@ -453,9 +565,7 @@ proc_capture_transformations (struct dataset *ds)
   assert (ds->temporary_trns_chain == NULL);
   chain = ds->permanent_trns_chain;
   ds->cur_trns_chain = ds->permanent_trns_chain = trns_chain_create ();
-
-  if ( ds->xform_callback)
-    ds->xform_callback (false, ds->xform_callback_aux);
+  dataset_transformations_changed__ (ds, false);
 
   return chain;
 }
@@ -467,8 +577,7 @@ void
 add_transformation (struct dataset *ds, trns_proc_func *proc, trns_free_func *free, void *aux)
 {
   trns_chain_append (ds->cur_trns_chain, NULL, proc, free, aux);
-  if ( ds->xform_callback)
-    ds->xform_callback (true, ds->xform_callback_aux);
+  dataset_transformations_changed__ (ds, true);
 }
 
 /* Adds a transformation that processes a case with PROC and
@@ -483,9 +592,7 @@ add_transformation_with_finalizer (struct dataset *ds,
                                    trns_free_func *free, void *aux)
 {
   trns_chain_append (ds->cur_trns_chain, finalize, proc, free, aux);
-
-  if ( ds->xform_callback)
-    ds->xform_callback (true, ds->xform_callback_aux);
+  dataset_transformations_changed__ (ds, true);
 }
 
 /* Returns the index of the next transformation.
@@ -520,9 +627,7 @@ proc_start_temporary_transformations (struct dataset *ds)
 
       trns_chain_finalize (ds->permanent_trns_chain);
       ds->temporary_trns_chain = ds->cur_trns_chain = trns_chain_create ();
-
-      if ( ds->xform_callback)
-       ds->xform_callback (true, ds->xform_callback_aux);
+      dataset_transformations_changed__ (ds, true);
     }
 }
 
@@ -562,11 +667,8 @@ proc_cancel_temporary_transformations (struct dataset *ds)
 
       trns_chain_destroy (ds->temporary_trns_chain);
       ds->temporary_trns_chain = NULL;
-
-      if ( ds->xform_callback)
-       ds->xform_callback (!trns_chain_is_empty (ds->permanent_trns_chain),
-                           ds->xform_callback_aux);
-
+      dataset_transformations_changed__ (
+        ds, !trns_chain_is_empty (ds->permanent_trns_chain));
       return true;
     }
   else
@@ -584,65 +686,11 @@ proc_cancel_all_transformations (struct dataset *ds)
   ok = trns_chain_destroy (ds->temporary_trns_chain) && ok;
   ds->permanent_trns_chain = ds->cur_trns_chain = trns_chain_create ();
   ds->temporary_trns_chain = NULL;
-  if ( ds->xform_callback)
-    ds->xform_callback (false, ds->xform_callback_aux);
+  dataset_transformations_changed__ (ds, false);
 
   return ok;
 }
 \f
-
-static void
-dict_callback (struct dictionary *d UNUSED, void *ds_)
-{
-  struct dataset *ds = ds_;
-  dataset_set_unsaved (ds);
-}
-
-/* Initializes procedure handling. */
-struct dataset *
-create_dataset (void)
-{
-  struct dataset *ds = xzalloc (sizeof(*ds));
-  ds->dict = dict_create ();
-
-  dict_set_change_callback (ds->dict, dict_callback, ds);
-
-  dict_set_encoding (ds->dict, get_default_encoding ());
-
-  ds->caseinit = caseinit_create ();
-  proc_cancel_all_transformations (ds);
-
-  ds->syntax_encoding = xstrdup ("Auto");
-
-  return ds;
-}
-
-
-void
-dataset_add_transform_change_callback (struct dataset *ds,
-                                      transformation_change_callback_func *cb,
-                                      void *aux)
-{
-  ds->xform_callback = cb;
-  ds->xform_callback_aux = aux;
-}
-
-/* Finishes up procedure handling. */
-void
-destroy_dataset (struct dataset *ds)
-{
-  proc_discard_active_file (ds);
-  dict_destroy (ds->dict);
-  caseinit_destroy (ds->caseinit);
-  trns_chain_destroy (ds->permanent_trns_chain);
-
-  if ( ds->xform_callback)
-    ds->xform_callback (false, ds->xform_callback_aux);
-
-  free (ds->syntax_encoding);
-  free (ds);
-}
-
 /* Causes output from the next procedure to be discarded, instead
    of being preserved for use as input for the next procedure. */
 void
@@ -651,77 +699,8 @@ proc_discard_output (struct dataset *ds)
   ds->discard_output = true;
 }
 
-/* Discards the active file dictionary, data, and
-   transformations. */
-void
-proc_discard_active_file (struct dataset *ds)
-{
-  assert (ds->proc_state == PROC_COMMITTED);
-
-  dict_clear (ds->dict);
-  fh_set_default_handle (NULL);
-
-  ds->n_lag = 0;
-
-  casereader_destroy (ds->source);
-  ds->source = NULL;
-
-  proc_cancel_all_transformations (ds);
-}
 
-/* Sets SOURCE as the source for procedure input for the next
-   procedure. */
-void
-proc_set_active_file (struct dataset *ds,
-                      struct casereader *source,
-                      struct dictionary *dict)
-{
-  assert (ds->proc_state == PROC_COMMITTED);
-  assert (ds->dict != dict);
-
-  proc_discard_active_file (ds);
-
-  dict_destroy (ds->dict);
-  ds->dict = dict;
-  dict_set_change_callback (ds->dict, dict_callback, ds);
-
-  proc_set_active_file_data (ds, source);
-}
-
-/* Replaces the active file's data by READER without replacing
-   the associated dictionary. */
-bool
-proc_set_active_file_data (struct dataset *ds, struct casereader *reader)
-{
-  casereader_destroy (ds->source);
-  ds->source = reader;
-
-  caseinit_clear (ds->caseinit);
-  caseinit_mark_as_preinited (ds->caseinit, ds->dict);
-
-  return reader == NULL || !casereader_error (reader);
-}
-
-/* Returns true if an active file data source is available, false
-   otherwise. */
-bool
-proc_has_active_file (const struct dataset *ds)
-{
-  return ds->source != NULL;
-}
-
-/* Returns the active file data source from DS, or a null pointer
-   if DS has no data source, and removes it from DS. */
-struct casereader *
-proc_extract_active_file_data (struct dataset *ds)
-{
-  struct casereader *reader = ds->source;
-  ds->source = NULL;
-
-  return reader;
-}
-
-/* Checks whether DS has a corrupted active file.  If so,
+/* Checks whether DS has a corrupted active dataset.  If so,
    discards it and returns false.  If not, returns true without
    doing anything. */
 bool
@@ -731,7 +710,7 @@ dataset_end_of_command (struct dataset *ds)
     {
       if (casereader_error (ds->source))
         {
-          proc_discard_active_file (ds);
+          dataset_clear (ds);
           return false;
         }
       else
@@ -816,20 +795,22 @@ filter_trns_proc (void *filter_var_,
 }
 
 
-struct dictionary *
-dataset_dict (const struct dataset *ds)
+void
+dataset_need_lag (struct dataset *ds, int n_before)
 {
-  return ds->dict;
+  ds->n_lag = MAX (ds->n_lag, n_before);
 }
-
-const struct casereader *
-dataset_source (const struct dataset *ds)
+\f
+static void
+dataset_changed__ (struct dataset *ds)
 {
-  return ds->source;
+  if (ds->callbacks != NULL && ds->callbacks->changed != NULL)
+    ds->callbacks->changed (ds->cb_data);
 }
 
-void
-dataset_need_lag (struct dataset *ds, int n_before)
+static void
+dataset_transformations_changed__ (struct dataset *ds, bool non_empty)
 {
-  ds->n_lag = MAX (ds->n_lag, n_before);
+  if (ds->callbacks != NULL && ds->callbacks->transformations_changed != NULL)
+    ds->callbacks->transformations_changed (non_empty, ds->cb_data);
 }