+ if (!prev)
+ prev = xnmalloc (mf->n_input_vars, sizeof *prev);
+ memcpy (prev, d, mf->n_input_vars * sizeof *prev);
+ }
+
+ /* Usually users don't provide the CONTENTS subcommand with ROWTYPE_, but
+ if they did then warn if ROWTYPE_ is an unexpected type. */
+ if (mf->factor_rowtype_mask || mf->pooled_rowtype_mask)
+ {
+ const char *name = rowtype_name (rt).string;
+ if (is_pooled (mf, d))
+ {
+ if (!((1u << rt) & mf->pooled_rowtype_mask))
+ parse_warning (r, NULL, _("Data contains pooled row type %s not "
+ "included in CONTENTS."), name);
+ }
+ else
+ {
+ if (!((1u << rt) & mf->factor_rowtype_mask))
+ parse_warning (r, NULL, _("Data contains with-factors row type "
+ "%s not included in CONTENTS."), name);
+ }
+ }
+
+ /* Initialize the matrix to be filled-in. */
+ int n_dims = rowtype_dimensions (rt);
+ const struct matrix_sched *ms = &mf->ms[n_dims];
+ matrix_sched_init (mf, rt, m);
+
+ enum rowtype rt_next;
+ bool eof;
+
+ size_t n_rows;
+ for (n_rows = 1; ; n_rows++)
+ {
+ if (n_rows <= ms->n_rp)
+ {
+ const struct row_sched *rs = &ms->rp[n_rows - 1];
+ size_t y = rs->y;
+ for (size_t x = rs->x0; x < rs->x1; x++)
+ {
+ double e;
+ if (!next_number (&p, r, &e))
+ goto exit;
+ gsl_matrix_set (m, y, x, e);
+ if (n_dims == 2 && mf->triangle != FULL)
+ gsl_matrix_set (m, x, y, e);
+ }
+ check_eol (mf, &p, r);
+ }
+ else
+ {
+ /* Suppress bad input data. We'll issue an error later. */
+ p.length = 0;
+ }
+
+ eof = (!more_tokens (&p, r)
+ || !read_id_columns (mf, &p, r, d_next, &rt_next));
+ if (eof)
+ break;
+
+ if (!equal_id_columns (mf, d, d_next) || rt_next != rt)
+ break;
+ }
+ if (!suppress_output)
+ matrix_sched_output (mf, rt, m, d, 0, w);
+
+ if (n_rows != ms->n_rp)
+ parse_error (r, NULL,
+ _("Matrix %s had %zu rows but %zu rows were expected."),
+ rowtype_name (rt).string, n_rows, ms->n_rp);
+ if (eof)
+ break;
+
+ double *d_tmp = d;
+ d = d_next;
+ d_next = d_tmp;
+
+ rt = rt_next;
+ }
+
+exit:
+ free (prev);
+ gsl_matrix_free (m);
+ free (d);
+ free (d_next);