Improve error messages for missing subcommands.
[pspp] / src / language / dictionary / vector.c
index a884331ce30ba33eb3a7a3c01be318f9ea9a32d5..fe1ab99e145227b2e808d23920ff7ae9c50ed7f9 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2010, 2011, 2012, 2016 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
 
 #include <stdlib.h>
 
-#include <data/format.h>
-#include <data/procedure.h>
-#include <data/dictionary.h>
-#include <data/variable.h>
-#include <language/command.h>
-#include <language/lexer/format-parser.h>
-#include <language/lexer/lexer.h>
-#include <language/lexer/variable-parser.h>
-#include <libpspp/assertion.h>
-#include <libpspp/message.h>
-#include <libpspp/misc.h>
-#include <libpspp/pool.h>
-#include <libpspp/str.h>
-
-#include "intprops.h"
-#include "xalloc.h"
+#include "data/dataset.h"
+#include "data/format.h"
+#include "data/dictionary.h"
+#include "data/variable.h"
+#include "language/command.h"
+#include "language/lexer/format-parser.h"
+#include "language/lexer/lexer.h"
+#include "language/lexer/variable-parser.h"
+#include "libpspp/assertion.h"
+#include "libpspp/i18n.h"
+#include "libpspp/message.h"
+#include "libpspp/misc.h"
+#include "libpspp/pool.h"
+#include "libpspp/str.h"
+
+#include "gl/intprops.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
@@ -47,37 +48,46 @@ cmd_vector (struct lexer *lexer, struct dataset *ds)
   do
     {
       char **vectors;
-      size_t vector_cnt, vector_cap;
+      size_t n_vectors, allocated_vectors;
 
       /* Get the name(s) of the new vector(s). */
       if (!lex_force_id (lexer))
        return CMD_CASCADING_FAILURE;
+      char *error = dict_id_is_valid__ (dict, lex_tokcstr (lexer));
+      if (error)
+        {
+          lex_error (lexer, "%s", error);
+          free (error);
+          return CMD_CASCADING_FAILURE;
+        }
 
       vectors = NULL;
-      vector_cnt = vector_cap = 0;
+      n_vectors = allocated_vectors = 0;
       while (lex_token (lexer) == T_ID)
        {
           size_t i;
 
-         if (dict_lookup_vector (dict, lex_tokid (lexer)))
+         if (dict_lookup_vector (dict, lex_tokcstr (lexer)))
            {
-             msg (SE, _("A vector named %s already exists."),
-                   lex_tokid (lexer));
+             lex_next_error (lexer, 0, 0,
+                              _("A vector named %s already exists."),
+                              lex_tokcstr (lexer));
              goto fail;
            }
 
-          for (i = 0; i < vector_cnt; i++)
-            if (!strcasecmp (vectors[i], lex_tokid (lexer)))
+          for (i = 0; i < n_vectors; i++)
+            if (!utf8_strcasecmp (vectors[i], lex_tokcstr (lexer)))
              {
-               msg (SE, _("Vector name %s is given twice."),
-                     lex_tokid (lexer));
+               lex_next_error (lexer, 0, 0,
+                                _("Vector name %s is given twice."),
+                                lex_tokcstr (lexer));
                goto fail;
              }
 
-          if (vector_cnt == vector_cap)
-            vectors = pool_2nrealloc (pool,
-                                       vectors, &vector_cap, sizeof *vectors);
-          vectors[vector_cnt++] = pool_strdup (pool, lex_tokid (lexer));
+          if (n_vectors == allocated_vectors)
+            vectors = pool_2nrealloc (pool, vectors, &allocated_vectors,
+                                      sizeof *vectors);
+          vectors[n_vectors++] = pool_strdup (pool, lex_tokcstr (lexer));
 
          lex_get (lexer);
          lex_match (lexer, T_COMMA);
@@ -91,10 +101,10 @@ cmd_vector (struct lexer *lexer, struct dataset *ds)
           struct variable **v;
           size_t nv;
 
-         if (vector_cnt > 1)
+         if (n_vectors > 1)
            {
-             msg (SE, _("A slash must separate each vector "
-                         "specification in VECTOR's long form."));
+             lex_error (lexer, _("A slash must separate each vector "
+                                  "specification in VECTOR's long form."));
              goto fail;
            }
 
@@ -107,35 +117,24 @@ cmd_vector (struct lexer *lexer, struct dataset *ds)
       else if (lex_match (lexer, T_LPAREN))
        {
           /* Short form. */
-          struct fmt_spec format;
+          struct fmt_spec format = fmt_for_output (FMT_F, 8, 2);
           bool seen_format = false;
-
-          struct variable **vars;
-          int var_cnt;
-
-          size_t i;
-
-          var_cnt = 0;
-          format = fmt_for_output (FMT_F, 8, 2);
-          seen_format = false;
+          size_t n_vars = 0;
+          int start_ofs = lex_ofs (lexer) - 2;
           while (!lex_match (lexer, T_RPAREN))
             {
-              if (lex_is_integer (lexer) && var_cnt == 0)
+              if (lex_is_integer (lexer) && n_vars == 0)
                 {
-                  var_cnt = lex_integer (lexer);
+                  if (!lex_force_int_range (lexer, NULL, 1, INT_MAX))
+                    goto fail;
+                  n_vars = lex_integer (lexer);
                   lex_get (lexer);
-                  if (var_cnt <= 0)
-                    {
-                      msg (SE, _("Vectors must have at least one element."));
-                      goto fail;
-                    }
                 }
               else if (lex_token (lexer) == T_ID && !seen_format)
                 {
                   seen_format = true;
                   if (!parse_format_specifier (lexer, &format)
-                      || !fmt_check_output (&format)
-                      || !fmt_check_type_compat (&format, VAL_NUMERIC))
+                      || !fmt_check_output (&format))
                     goto fail;
                 }
               else
@@ -145,48 +144,54 @@ cmd_vector (struct lexer *lexer, struct dataset *ds)
                 }
               lex_match (lexer, T_COMMA);
             }
-          if (var_cnt == 0)
+          int end_ofs = lex_ofs (lexer) - 1;
+          if (n_vars == 0)
             {
-              lex_error (lexer, _("expecting vector length"));
+              lex_error (lexer, _("Syntax error expecting vector length."));
               goto fail;
             }
 
-         /* Check that none of the variables exist and that
-             their names are no more than VAR_NAME_LEN bytes
-             long. */
-          for (i = 0; i < vector_cnt; i++)
+         /* Check that none of the variables exist and that their names are
+             not excessively long. */
+          for (size_t i = 0; i < n_vectors; i++)
            {
               int j;
-             for (j = 0; j < var_cnt; j++)
+             for (j = 0; j < n_vars; j++)
                {
-                  char name[VAR_NAME_LEN + INT_STRLEN_BOUND (int) + 1];
-                 sprintf (name, "%s%d", vectors[i], j + 1);
-                  if (strlen (name) > VAR_NAME_LEN)
+                  char *name = xasprintf ("%s%d", vectors[i], j + 1);
+                  char *error = dict_id_is_valid__ (dict, name);
+                  if (error)
                     {
-                      msg (SE, _("%s is too long for a variable name."), name);
+                      lex_ofs_error (lexer, start_ofs, end_ofs, "%s", error);
+                      free (error);
+                      free (name);
                       goto fail;
                     }
                   if (dict_lookup_var (dict, name))
                    {
-                     msg (SE, _("%s is an existing variable name."), name);
+                     lex_ofs_error (lexer, start_ofs, end_ofs,
+                                     _("%s is an existing variable name."),
+                                     name);
+                      free (name);
                      goto fail;
                    }
+                  free (name);
                }
            }
 
          /* Finally create the variables and vectors. */
-          vars = pool_nmalloc (pool, var_cnt, sizeof *vars);
-          for (i = 0; i < vector_cnt; i++)
+          struct variable **vars = pool_nmalloc (pool, n_vars, sizeof *vars);
+          for (size_t i = 0; i < n_vectors; i++)
            {
-              int j;
-             for (j = 0; j < var_cnt; j++)
+             for (size_t j = 0; j < n_vars; j++)
                {
-                  char name[VAR_NAME_LEN + 1];
-                 sprintf (name, "%s%d", vectors[i], j + 1);
-                 vars[j] = dict_create_var_assert (dict, name, 0);
+                  char *name = xasprintf ("%s%zu", vectors[i], j + 1);
+                 vars[j] = dict_create_var_assert (dict, name,
+                                                    fmt_var_width (&format));
                   var_set_both_formats (vars[j], &format);
+                  free (name);
                }
-              dict_create_vector_assert (dict, vectors[i], vars, var_cnt);
+              dict_create_vector_assert (dict, vectors[i], vars, n_vars);
            }
        }
       else
@@ -198,7 +203,7 @@ cmd_vector (struct lexer *lexer, struct dataset *ds)
   while (lex_match (lexer, T_SLASH));
 
   pool_destroy (pool);
-  return lex_end_of_command (lexer);
+  return CMD_SUCCESS;
 
 fail:
   pool_destroy (pool);