+ if (!mg)
+ return;
+
+ for (size_t i = 0; i < mg->n_vars; i++)
+ {
+ struct mg_var *mgv = &mg->vars[i];
+ var_set_measure (mgv->var, mg_var_interpret (mgv));
+ mg_var_uninit (mgv);
+ }
+ free (mg->vars);
+ free (mg);
+}
+
+/* Adds final measurement levels based on MG, after all the cases have been
+ added. */
+static void
+measure_guesser_commit (struct measure_guesser *mg)
+{
+ for (size_t i = 0; i < mg->n_vars; i++)
+ {
+ struct mg_var *mgv = &mg->vars[i];
+ var_set_measure (mgv->var, mg_var_interpret (mgv));
+ }
+}
+
+/* Passes the cases in READER through MG and uses the data in the cases to set
+ measurement levels for the variables where they were still unknown. */
+void
+measure_guesser_run (struct measure_guesser *mg,
+ const struct casereader *reader)
+{
+ struct casereader *r = casereader_clone (reader);
+ while (mg->n_vars > 0)
+ {
+ struct ccase *c = casereader_read (r);
+ if (!c)
+ break;
+ measure_guesser_add_case (mg, c);
+ case_unref (c);
+ }
+ casereader_destroy (r);
+
+ measure_guesser_commit (mg);
+}
+\f
+/* A transformation for guessing measurement levels. */
+
+static enum trns_result
+mg_trns_proc (void *mg_, struct ccase **c, casenumber case_nr UNUSED)
+{
+ struct measure_guesser *mg = mg_;
+ measure_guesser_add_case (mg, *c);
+ return TRNS_CONTINUE;
+}
+
+static bool
+mg_trns_free (void *mg_)
+{
+ struct measure_guesser *mg = mg_;
+ measure_guesser_commit (mg);
+ measure_guesser_destroy (mg);
+ return true;
+}
+
+static const struct trns_class mg_trns_class = {
+ .name = "add measurement level",
+ .execute = mg_trns_proc,
+ .destroy = mg_trns_free,
+};
+
+static void
+add_measurement_level_trns (struct dataset *ds, struct dictionary *dict)
+{
+ struct measure_guesser *mg = measure_guesser_create__ (dict);
+ if (mg)
+ add_transformation (ds, &mg_trns_class, mg);
+}
+
+static void
+cancel_measurement_level_trns (struct trns_chain *chain)
+{
+ if (!chain->n)
+ return;
+
+ struct transformation *trns = &chain->xforms[chain->n - 1];
+ if (trns->class != &mg_trns_class)
+ return;
+
+ struct measure_guesser *mg = trns->aux;
+ measure_guesser_destroy (mg);
+ chain->n--;
+}
+\f
+static void
+dataset_changed__ (struct dataset *ds)
+{
+ if (ds->callbacks != NULL && ds->callbacks->changed != NULL)
+ ds->callbacks->changed (ds->cb_data);
+}
+
+static void
+dataset_transformations_changed__ (struct dataset *ds, bool non_empty)
+{
+ if (ds->callbacks != NULL && ds->callbacks->transformations_changed != NULL)
+ ds->callbacks->transformations_changed (non_empty, ds->cb_data);
+}
+\f
+/* Private interface for use by session code. */
+
+void
+dataset_set_session__ (struct dataset *ds, struct session *session)
+{
+ ds->session = session;