+ if (dict_lookup_var (dict, "VARNAME_"))
+ {
+ msg (SE, _("VARIABLES may not include VARNAME_."));
+ dict_unref (dict);
+ return NULL;
+ }
+ return dict;
+}
+
+static bool
+parse_matrix_data_subvars (struct lexer *lexer, struct dictionary *dict,
+ bool *taken_vars,
+ struct variable ***vars, size_t **indexes,
+ size_t *n_vars)
+{
+ if (!parse_variables (lexer, dict, vars, n_vars, 0))
+ return false;
+
+ *indexes = xnmalloc (*n_vars, sizeof **indexes);
+ for (size_t i = 0; i < *n_vars; i++)
+ {
+ struct variable *v = (*vars)[i];
+ if (!strcasecmp (var_get_name (v), "ROWTYPE_"))
+ {
+ msg (SE, _("ROWTYPE_ is not allowed on SPLIT or FACTORS."));
+ goto error;
+ }
+ (*indexes)[i] = var_get_dict_index (v);
+
+ bool *tv = &taken_vars[var_get_dict_index (v)];
+ if (*tv)
+ {
+ msg (SE, _("%s may not appear on both SPLIT and FACTORS."),
+ var_get_name (v));
+ goto error;
+ }
+ *tv = true;
+
+ var_set_both_formats (v, &(struct fmt_spec) { .type = FMT_F, .w = 4 });
+ }
+ return true;
+
+error:
+ free (*vars);
+ *vars = NULL;
+ *n_vars = 0;
+ free (*indexes);
+ *indexes = NULL;
+ return false;
+}
+
+int
+cmd_matrix_data (struct lexer *lexer, struct dataset *ds)
+{
+ struct dictionary *dict = parse_matrix_data_variables (lexer);
+ if (!dict)
+ return CMD_FAILURE;
+
+ size_t n_input_vars = dict_get_n_vars (dict);
+ struct variable **input_vars = xnmalloc (n_input_vars, sizeof *input_vars);
+ for (size_t i = 0; i < n_input_vars; i++)
+ input_vars[i] = dict_get_var (dict, i);
+
+ int varname_width = 8;
+ for (size_t i = 0; i < n_input_vars; i++)
+ {
+ int w = strlen (var_get_name (input_vars[i]));
+ varname_width = MAX (w, varname_width);
+ }
+
+ struct variable *rowtype = dict_lookup_var (dict, "ROWTYPE_");
+ bool input_rowtype = rowtype != NULL;
+ if (!rowtype)
+ rowtype = dict_create_var_assert (dict, "ROWTYPE_", 8);
+
+ struct matrix_format mf = {
+ .input_rowtype = input_rowtype,
+ .input_vars = input_vars,
+ .n_input_vars = n_input_vars,
+
+ .rowtype = rowtype,
+ .varname = dict_create_var_assert (dict, "VARNAME_", varname_width),
+
+ .triangle = LOWER,
+ .diagonal = DIAGONAL,
+ .n = -1,
+ .cells = -1,
+ };
+
+ bool *taken_vars = XCALLOC (n_input_vars, bool);
+ if (input_rowtype)
+ taken_vars[var_get_dict_index (rowtype)] = true;
+
+ struct file_handle *fh = NULL;