GET is well tested.
[pspp] / src / language / stats / matrix.c
index bcae19971750704affa257ef127ca17693ed9b53..5214ee3d8be73b5b1c088cbe64ea659cb770cf18 100644 (file)
@@ -3432,9 +3432,11 @@ struct matrix_cmd
         struct get_command
           {
             struct matrix_lvalue *dst;
+            struct dataset *dataset;
             struct file_handle *file;
             char *encoding;
-            struct string_array variables;
+            struct var_syntax *vars;
+            size_t n_vars;
             struct matrix_var *names;
 
             /* Treatment of missing values. */
@@ -5354,6 +5356,7 @@ matrix_parse_get (struct matrix_state *s)
   *cmd = (struct matrix_cmd) {
     .type = MCMD_GET,
     .get = {
+      .dataset = s->dataset,
       .user = { .treatment = MGET_ERROR },
       .system = { .treatment = MGET_ERROR },
     }
@@ -5368,25 +5371,20 @@ matrix_parse_get (struct matrix_state *s)
     {
       if (lex_match_id (s->lexer, "FILE"))
         {
-          if (get->variables.n)
-            {
-              lex_error (s->lexer, _("FILE must precede VARIABLES"));
-              goto error;
-            }
           lex_match (s->lexer, T_EQUALS);
 
           fh_unref (get->file);
-          get->file = fh_parse (s->lexer, FH_REF_FILE, s->session);
-          if (!get->file)
-            goto error;
+          if (lex_match (s->lexer, T_ASTERISK))
+            get->file = NULL;
+          else
+            {
+              get->file = fh_parse (s->lexer, FH_REF_FILE, s->session);
+              if (!get->file)
+                goto error;
+            }
         }
       else if (lex_match_id (s->lexer, "ENCODING"))
        {
-          if (get->variables.n)
-            {
-              lex_error (s->lexer, _("ENCODING must precede VARIABLES"));
-              goto error;
-            }
          lex_match (s->lexer, T_EQUALS);
          if (!lex_force_string (s->lexer))
            goto error;
@@ -5400,40 +5398,14 @@ matrix_parse_get (struct matrix_state *s)
         {
           lex_match (s->lexer, T_EQUALS);
 
-          struct dictionary *dict = NULL;
-          if (!get->file)
-            {
-              dict = dataset_dict (s->dataset);
-              if (dict_get_var_cnt (dict) == 0)
-                {
-                  lex_error (s->lexer, _("GET cannot read empty active file."));
-                  goto error;
-                }
-            }
-          else
-            {
-              struct casereader *reader = any_reader_open_and_decode (
-                get->file, get->encoding, &dict, NULL);
-              if (!reader)
-                goto error;
-              casereader_destroy (reader);
-            }
-
-          struct variable **vars;
-          size_t n_vars;
-          bool ok = parse_variables (s->lexer, dict, &vars, &n_vars,
-                                     PV_DUPLICATE | PV_NUMERIC | PV_NO_SCRATCH);
-          if (!ok)
+          if (get->n_vars)
             {
-              dict_unref (dict);
+              lex_sbc_only_once ("VARIABLES");
               goto error;
             }
 
-          string_array_clear (&get->variables);
-          for (size_t i = 0; i < n_vars; i++)
-            string_array_append (&get->variables, var_get_name (vars[i]));
-          free (vars);
-          dict_unref (dict);
+          if (!var_syntax_parse (s->lexer, &get->vars, &get->n_vars))
+            goto error;
         }
       else if (lex_match_id (s->lexer, "NAMES"))
         {
@@ -5502,59 +5474,34 @@ error:
 }
 
 static void
-matrix_cmd_execute_get (struct get_command *get)
+matrix_cmd_execute_get__ (struct get_command *get,
+                          const struct dictionary *dict,
+                          struct casereader *reader)
 {
-  assert (get->file);           /* XXX */
-
-  struct dictionary *dict;
-  struct casereader *reader = any_reader_open_and_decode (
-    get->file, get->encoding, &dict, NULL);
-  if (!reader)
-    return;
-
-  const struct variable **vars = xnmalloc (
-    get->variables.n ? get->variables.n : dict_get_var_cnt (dict),
-    sizeof *vars);
+  struct variable **vars;
   size_t n_vars = 0;
 
-  if (get->variables.n)
+  if (get->n_vars)
     {
-      for (size_t i = 0; i < get->variables.n; i++)
-        {
-          const char *name = get->variables.strings[i];
-          const struct variable *var = dict_lookup_var (dict, name);
-          if (!var)
-            {
-              msg (SE, _("GET: Data file does not contain variable %s."),
-                   name);
-              dict_unref (dict);
-              free (vars);
-              return;
-            }
-          if (!var_is_numeric (var))
-            {
-              msg (SE, _("GET: Variable %s is not numeric."), name);
-              dict_unref (dict);
-              free (vars);
-              return;
-            }
-          vars[n_vars++] = var;
-        }
+      if (!var_syntax_evaluate (get->vars, get->n_vars, dict,
+                                &vars, &n_vars, PV_NUMERIC))
+        return;
     }
   else
     {
-      for (size_t i = 0; i < dict_get_var_cnt (dict); i++)
+      n_vars = dict_get_var_cnt (dict);
+      vars = xnmalloc (n_vars, sizeof *vars);
+      for (size_t i = 0; i < n_vars; i++)
         {
-          const struct variable *var = dict_get_var (dict, i);
+          struct variable *var = dict_get_var (dict, i);
           if (!var_is_numeric (var))
             {
               msg (SE, _("GET: Variable %s is not numeric."),
                    var_get_name (var));
-              dict_unref (dict);
               free (vars);
               return;
             }
-          vars[n_vars++] = var;
+          vars[i] = var;
         }
     }
 
@@ -5632,7 +5579,6 @@ matrix_cmd_execute_get (struct get_command *get)
       if (keep)
         n_rows++;
     }
-  casereader_destroy (reader);
   if (!error)
     {
       m->size1 = n_rows;
@@ -5640,9 +5586,39 @@ matrix_cmd_execute_get (struct get_command *get)
     }
   else
     gsl_matrix_free (m);
-  dict_unref (dict);
   free (vars);
 }
+
+static void
+matrix_cmd_execute_get (struct get_command *get)
+{
+  struct dictionary *dict;
+  struct casereader *reader;
+  if (get->file)
+    {
+       reader = any_reader_open_and_decode (get->file, get->encoding,
+                                            &dict, NULL);
+       if (!reader)
+         return;
+    }
+  else
+    {
+      if (dict_get_var_cnt (dataset_dict (get->dataset)) == 0)
+        {
+          msg (ME, _("GET cannot read empty active file."));
+          return;
+        }
+      reader = proc_open (get->dataset);
+      dict = dict_ref (dataset_dict (get->dataset));
+    }
+
+  matrix_cmd_execute_get__ (get, dict, reader);
+
+  dict_unref (dict);
+  casereader_destroy (reader);
+  if (!get->file)
+    proc_commit (get->dataset);
+}
 \f
 static const char *
 match_rowtype (struct lexer *lexer)
@@ -6672,7 +6648,7 @@ matrix_cmd_destroy (struct matrix_cmd *cmd)
       matrix_lvalue_destroy (cmd->get.dst);
       fh_unref (cmd->get.file);
       free (cmd->get.encoding);
-      string_array_destroy (&cmd->get.variables);
+      var_syntax_destroy (cmd->get.vars, cmd->get.n_vars);
       break;
 
     case MCMD_MSAVE:
@@ -6773,6 +6749,7 @@ cmd_matrix (struct lexer *lexer, struct dataset *ds)
     return CMD_FAILURE;
 
   struct matrix_state state = {
+    .dataset = ds,
     .session = dataset_session (ds),
     .lexer = lexer,
     .vars = HMAP_INITIALIZER (state.vars),