Cite tokens when reporting invalid identifiers.
authorBen Pfaff <blp@cs.stanford.edu>
Sat, 10 Sep 2022 18:04:21 +0000 (11:04 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Sat, 10 Sep 2022 18:09:44 +0000 (11:09 -0700)
These functions weren't able to cite a specific token in cases where that
was appropriate.  This fixes the problem.

25 files changed:
perl-module/PSPP.xs
src/data/dictionary.c
src/data/dictionary.h
src/data/identifier.h
src/data/identifier2.c
src/data/mrset.c
src/data/mrset.h
src/data/pc+-file-reader.c
src/data/por-file-reader.c
src/data/sys-file-reader.c
src/data/vector.c
src/language/control/define.c
src/language/data-io/get-data.c
src/language/data-io/trim.c
src/language/dictionary/attributes.c
src/language/dictionary/mrsets.c
src/language/dictionary/sys-file-info.c
src/language/dictionary/vector.c
src/language/lexer/variable-parser.c
src/language/stats/flip.c
src/language/stats/matrix.c
src/ui/gui/psppire-dict.c
src/ui/gui/psppire-dict.h
src/ui/gui/psppire-variable-sheet.c
tests/language/dictionary/mrsets.at

index 077bf581f0031cfe27332efbbf54c2dbec6e04a3..1f05be2a65cf81ae626f9dc208ee182dec623508 100644 (file)
@@ -368,7 +368,7 @@ pxs_dict_create_var (dict, name, ip_fmt)
 INIT:
  SV *errstr = get_sv("PSPP::errstr", TRUE);
  sv_setpv (errstr, "");
- if ( ! id_is_plausible (name, false))
+ if ( ! id_is_plausible (name))
   {
     sv_setpv (errstr, "The variable name is not valid.");
     XSRETURN_UNDEF;
index a2e3fb8fc1ee2a6e42d6d287eb6bd3047cee9277..60349bce61ec4650b8287f2e28b9bcff5973ac66 100644 (file)
@@ -179,15 +179,35 @@ dict_get_encoding (const struct dictionary *d)
   return d->encoding ;
 }
 
+/* Checks whether UTF-8 string ID is an acceptable identifier in DICT's
+   encoding.  Returns true if it is, otherwise an error message that the caller
+   must free(). */
+char * WARN_UNUSED_RESULT
+dict_id_is_valid__ (const struct dictionary *dict, const char *id)
+{
+  if (!dict->names_must_be_ids)
+    return NULL;
+  return id_is_valid__ (id, dict->encoding);
+}
+
+static bool
+error_to_bool (char *error)
+{
+  if (error)
+    {
+      free (error);
+      return false;
+    }
+  else
+    return true;
+}
+
 /* Returns true if UTF-8 string ID is an acceptable identifier in DICT's
-   encoding, false otherwise.  If ISSUE_ERROR is true, issues an explanatory
-   error message on failure. */
+   encoding, false otherwise. */
 bool
-dict_id_is_valid (const struct dictionary *dict, const char *id,
-                  bool issue_error)
+dict_id_is_valid (const struct dictionary *dict, const char *id)
 {
-  return (!dict->names_must_be_ids
-          || id_is_valid (id, dict->encoding, issue_error));
+  return error_to_bool (dict_id_is_valid__ (dict, id));
 }
 
 void
index 3e874d87071349bad38e253aaeb65b9b7a81f966..f709f11dd99324e1b45cae40186bc40296543988 100644 (file)
@@ -189,8 +189,9 @@ bool dict_has_attributes (const struct dictionary *);
 /* Data encoding. */
 const char *dict_get_encoding (const struct dictionary *d);
 
-bool dict_id_is_valid (const struct dictionary *, const char *id,
-                       bool issue_error);
+char *dict_id_is_valid__ (const struct dictionary *, const char *id)
+  WARN_UNUSED_RESULT;
+bool dict_id_is_valid (const struct dictionary *, const char *id);
 
 /* Internal variables. */
 struct variable *dict_create_internal_var (int case_idx, int width);
index dcbce970cda97168ab96a22c3e51660d33efc763..4a23dd7dd5db1079f47e9edab4d2e9a172e1ed96 100644 (file)
@@ -89,8 +89,11 @@ bool lex_is_keyword (enum token_type);
 /* Validating identifiers. */
 #define ID_MAX_LEN 64          /* Maximum length of identifier, in bytes. */
 
-bool id_is_valid (const char *id, const char *dict_encoding, bool issue_error);
-bool id_is_plausible (const char *id, bool issue_error);
+bool id_is_valid (const char *id, const char *dict_encoding);
+bool id_is_plausible (const char *id);
+char *id_is_valid__ (const char *id, const char *dict_encoding)
+  WARN_UNUSED_RESULT;
+char *id_is_plausible__ (const char *id) WARN_UNUSED_RESULT;
 
 /* Recognizing identifiers. */
 bool lex_is_id1 (char);
index 3b6458f02d513dd3f0d08c456fb4341c01862411..d21c6bba5b50eb59262eb10336b6f8b11f1273e6 100644 (file)
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-/* Returns true if UTF-8 string ID is an acceptable identifier in encoding
-   DICT_ENCODING (UTF-8 if null), false otherwise.  If ISSUE_ERROR is true,
-   issues an explanatory error message on failure. */
-bool
-id_is_valid (const char *id, const char *dict_encoding, bool issue_error)
+static bool
+error_to_bool (char *error)
 {
-  size_t dict_len;
+  if (error)
+    {
+      free (error);
+      return false;
+    }
+  else
+    return true;
+}
 
-  if (!id_is_plausible (id, issue_error))
-    return false;
+/* Checks whether if UTF-8 string ID is an acceptable identifier in encoding
+   DICT_ENCODING (UTF-8 if null).  Returns NULL if it is acceptable, otherwise
+   an error message that the caller must free(). */
+char * WARN_UNUSED_RESULT
+id_is_valid__ (const char *id, const char *dict_encoding)
+{
+  char *error = id_is_plausible__ (id);
+  if (error)
+    return error;
 
+  size_t dict_len;
   if (dict_encoding != NULL)
     {
       /* XXX need to reject recoded strings that contain the fallback
@@ -55,79 +67,74 @@ id_is_valid (const char *id, const char *dict_encoding, bool issue_error)
     dict_len = strlen (id);
 
   if (dict_len > ID_MAX_LEN)
-    {
-      if (issue_error)
-        msg (SE, _("Identifier `%s' exceeds %d-byte limit."),
-             id, ID_MAX_LEN);
-      return false;
-    }
+    return xasprintf (_("Identifier `%s' exceeds %d-byte limit."),
+                      id, ID_MAX_LEN);
 
-  return true;
+  return NULL;
 }
 
-/* Returns true if UTF-8 string ID is an plausible identifier, false
-   otherwise.  If ISSUE_ERROR is true, issues an explanatory error message on
-   failure.  */
+/* Returns true if UTF-8 string ID is an acceptable identifier in encoding
+   DICT_ENCODING (UTF-8 if null), false otherwise. */
 bool
-id_is_plausible (const char *id, bool issue_error)
+id_is_valid (const char *id, const char *dict_encoding)
 {
-  const uint8_t *bad_unit;
-  const uint8_t *s;
-  char ucname[16];
-  int mblen;
-  ucs4_t uc;
+  return error_to_bool (id_is_valid__ (id, dict_encoding));
+}
 
+/* Checks whether UTF-8 string ID is an plausible identifier.  Returns NULL if
+   it is, otherwise an error message that the caller must free().  */
+char * WARN_UNUSED_RESULT
+id_is_plausible__ (const char *id)
+{
   /* ID cannot be the empty string. */
   if (id[0] == '\0')
-    {
-      if (issue_error)
-        msg (SE, _("Identifier cannot be empty string."));
-      return false;
-    }
+    return xstrdup (_("Identifier cannot be empty string."));
 
   /* ID cannot be a reserved word. */
   if (lex_id_to_token (ss_cstr (id)) != T_ID)
-    {
-      if (issue_error)
-        msg (SE, _("`%s' may not be used as an identifier because it "
-                   "is a reserved word."), id);
-      return false;
-    }
+    return xasprintf (_("`%s' may not be used as an identifier because it "
+                        "is a reserved word."), id);
 
-  bad_unit = u8_check (CHAR_CAST (const uint8_t *, id), strlen (id));
+  const uint8_t *bad_unit = u8_check (CHAR_CAST (const uint8_t *, id),
+                                      strlen (id));
   if (bad_unit != NULL)
     {
       /* If this message ever appears, it probably indicates a PSPP bug since
          it shouldn't be possible to get invalid UTF-8 this far. */
-      if (issue_error)
-        msg (SE, _("`%s' may not be used as an identifier because it "
-                   "contains ill-formed UTF-8 at byte offset %tu."),
-             id, CHAR_CAST (const char *, bad_unit) - id);
-      return false;
+      return xasprintf (_("`%s' may not be used as an identifier because it "
+                          "contains ill-formed UTF-8 at byte offset %tu."),
+                        id, CHAR_CAST (const char *, bad_unit) - id);
     }
 
   /* Check that it is a valid identifier. */
-  mblen = u8_strmbtouc (&uc, CHAR_CAST (uint8_t *, id));
+  ucs4_t uc;
+  int mblen = u8_strmbtouc (&uc, CHAR_CAST (uint8_t *, id));
   if (!lex_uc_is_id1 (uc))
     {
-      if (issue_error)
-        msg (SE, _("Character %s (in `%s') may not appear "
-                   "as the first character in a identifier."),
-             uc_name (uc, ucname), id);
-      return false;
+      char ucname[16];
+      return xasprintf (_("Character %s (in `%s') may not appear "
+                          "as the first character in a identifier."),
+                        uc_name (uc, ucname), id);
     }
 
-  for (s = CHAR_CAST (uint8_t *, id + mblen);
+  for (const uint8_t *s = CHAR_CAST (uint8_t *, id + mblen);
        (mblen = u8_strmbtouc (&uc, s)) != 0;
         s += mblen)
     if (!lex_uc_is_idn (uc))
       {
-        if (issue_error)
-          msg (SE, _("Character %s (in `%s') may not appear in an "
-                     "identifier."),
-               uc_name (uc, ucname), id);
-        return false;
+        char ucname[16];
+        return xasprintf (_("Character %s (in `%s') may not appear in an "
+                            "identifier."),
+                          uc_name (uc, ucname), id);
       }
 
-  return true;
+  return NULL;
+}
+
+/* Returns true if UTF-8 string ID is an plausible identifier, false
+   otherwise. */
+bool
+id_is_plausible (const char *id)
+{
+  return error_to_bool (id_is_plausible__ (id));
 }
index 63f4b3fe339cc03248c3631e71132cd3c80e1384..c5e6cd2ec2b80b8302e277cd7a6fbfd4c491eea1 100644 (file)
@@ -67,26 +67,42 @@ mrset_destroy (struct mrset *mrset)
     }
 }
 
-/* Returns true if the UTF-8 encoded NAME is a valid name for a multiple
-   response set in a dictionary encoded in DICT_ENCODING, false otherwise.  If
-   ISSUE_ERROR is true, issues an explanatory error message on failure. */
-bool
-mrset_is_valid_name (const char *name, const char *dict_encoding,
-                     bool issue_error)
+/* Checks whether the UTF-8 encoded NAME is a valid name for a multiple
+   response set in a dictionary encoded in DICT_ENCODING.  Return NULL if it
+   is, otherwise an error message that the caller must free(). */
+char * WARN_UNUSED_RESULT
+mrset_is_valid_name__ (const char *name, const char *dict_encoding)
 {
-  if (!id_is_valid (name, dict_encoding, issue_error))
-    return false;
+  char *error = id_is_valid__ (name, dict_encoding);
+  if (error)
+    return error;
 
   if (name[0] != '$')
+    return xasprintf (_("%s is not a valid name for a multiple response "
+                        "set.  Multiple response set names must begin with "
+                        "`$'."), name);
+
+  return NULL;
+}
+
+static bool
+error_to_bool (char *error)
+{
+  if (error)
     {
-      if (issue_error)
-        msg (SE, _("%s is not a valid name for a multiple response "
-                   "set.  Multiple response set names must begin with "
-                   "`$'."), name);
+      free (error);
       return false;
     }
+  else
+    return true;
+}
 
-  return true;
+/* Returns true if the UTF-8 encoded NAME is a valid name for a multiple
+   response set in a dictionary encoded in DICT_ENCODING, false otherwise. */
+bool
+mrset_is_valid_name (const char *name, const char *dict_encoding)
+{
+  return error_to_bool (mrset_is_valid_name__ (name, dict_encoding));
 }
 
 /* Checks various constraints on MRSET:
@@ -112,7 +128,7 @@ mrset_ok (const struct mrset *mrset, const struct dictionary *dict)
   size_t i;
 
   if (mrset->name == NULL
-      || !mrset_is_valid_name (mrset->name, dict_get_encoding (dict), false)
+      || !mrset_is_valid_name (mrset->name, dict_get_encoding (dict))
       || (mrset->type != MRSET_MD && mrset->type != MRSET_MC)
       || mrset->vars == NULL
       || mrset->n_vars < 2)
index 9971924e0d39d2d9c1adb044e2c033d39b9ab77f..30d855ec3d62d43fca4c64c4b2d3f98c3ea4028a 100644 (file)
@@ -77,8 +77,9 @@ struct mrset
 struct mrset *mrset_clone (const struct mrset *);
 void mrset_destroy (struct mrset *);
 
-bool mrset_is_valid_name (const char *name, const char *dict_encoding,
-                          bool issue_error);
+char *mrset_is_valid_name__ (const char *name, const char *dict_encoding)
+  WARN_UNUSED_RESULT;
+bool mrset_is_valid_name (const char *name, const char *dict_encoding);
 
 bool mrset_ok (const struct mrset *, const struct dictionary *);
 
index 8e9cb94df79cff44bf79ca25a7e85ac59cfac753..5832df8d7f923a264149a069038941b851e87781 100644 (file)
@@ -851,7 +851,7 @@ parse_variable_records (struct pcp_reader *r, struct dictionary *dict,
       if (name[0] == '$')
         name = pool_asprintf (r->pool, "%s_", name + 1);
 
-      if (!dict_id_is_valid (dict, name, false) || name[0] == '#')
+      if (!dict_id_is_valid (dict, name) || name[0] == '#')
         {
           pcp_error (r, rec->pos, _("Invalid variable name `%s'."), name);
           return false;
index 8cea15e7496592588233047bcaf5d95e8e246bbf..7f32d2cf8f359d4ebd9dd718e58410abeb134448 100644 (file)
@@ -716,8 +716,7 @@ read_variables (struct pfm_reader *r, struct dictionary *dict)
       for (j = 0; j < 6; j++)
         fmt[j] = read_int (r);
 
-      if (!dict_id_is_valid (dict, name, false)
-          || *name == '#' || *name == '$')
+      if (!dict_id_is_valid (dict, name) || *name == '#' || *name == '$')
         error (r, _("Invalid variable name `%s' in position %d."), name, i);
       str_uppercase (name);
 
index fb4fa53acf20e8a24b4fa423887a88e6c2ae5610..88c0994dc35977f866228f90ee7036e914427eef 100644 (file)
@@ -1433,8 +1433,7 @@ parse_variable_records (struct sfm_reader *r, struct dictionary *dict,
         }
 
       struct variable *var;
-      if (!dict_id_is_valid (dict, name, false)
-          || name[0] == '$' || name[0] == '#')
+      if (!dict_id_is_valid (dict, name) || name[0] == '$' || name[0] == '#')
         {
           var = add_var_with_generated_name (dict, rec->width);
           sys_warn (r, rec->pos, _("Renaming variable with invalid name "
@@ -1817,7 +1816,7 @@ decode_mrsets (struct sfm_reader *r, struct dictionary *dict)
       size_t i;
 
       name = recode_string ("UTF-8", r->encoding, s->name, -1);
-      if (!mrset_is_valid_name (name, dict_get_encoding (dict), false))
+      if (!mrset_is_valid_name (name, dict_get_encoding (dict)))
         {
           sys_warn (r, -1, _("Invalid multiple response set name `%s'."),
                     name);
@@ -2051,7 +2050,7 @@ parse_long_var_name_map (struct sfm_reader *r,
   while (read_variable_to_value_pair (r, dict, text, &var, &long_name))
     {
       /* Validate long name. */
-      if (!dict_id_is_valid (dict, long_name, false)
+      if (!dict_id_is_valid (dict, long_name)
           || long_name[0] == '$' || long_name[0] == '#')
         {
           sys_warn (r, record->pos,
index c88d236df6c942057425baa7227cbf23ee02a49f..53378b4b048979b2f15abae2c60735f393fd35c7 100644 (file)
@@ -57,7 +57,7 @@ vector_create (const char *name, struct variable **vars, size_t n_vars)
   struct vector *vector = xmalloc (sizeof *vector);
 
   assert (n_vars > 0);
-  assert (id_is_plausible (name, false));
+  assert (id_is_plausible (name));
 
   vector->name = xstrdup (name);
   vector->vars = xmemdup (vars, n_vars * sizeof *vector->vars);
index 27f5093504a1cc4fbd96082f718586cd1e2984e9..14eafacb42ca71043a67d9cf82bb499db865bb4e 100644 (file)
@@ -103,7 +103,7 @@ cmd_define (struct lexer *lexer, struct dataset *ds UNUSED)
       return CMD_FAILURE;
     }
   const char *name = lex_tokcstr (lexer);
-  if (!id_is_plausible (name + (name[0] == '!'), false))
+  if (!id_is_plausible (name + (name[0] == '!')))
     {
       lex_error (lexer, _("Syntax error expecting identifier."));
       return CMD_FAILURE;
index e746e9a05c35d9c2e5203b3633e57e19d64b4e1f..cf96e415ade090795f11b6f40b52c3f3f3ee0225 100644 (file)
@@ -566,16 +566,14 @@ parse_get_txt (struct lexer *lexer, struct dataset *ds)
         }
 
       int name_ofs = lex_ofs (lexer);
-      const char * tstr = lex_tokcstr (lexer);
-      if (tstr == NULL)
-       {
-         lex_error (lexer, NULL);
-         goto error;
-       }
-      name = xstrdup (tstr);
-      if (!lex_force_id (lexer)
-          || !dict_id_is_valid (dict, name, true))
-       {
+      if (!lex_force_id (lexer))
+        goto error;
+      name = xstrdup (lex_tokcstr (lexer));
+      char *error = dict_id_is_valid__ (dict, name);
+      if (error)
+        {
+          lex_error (lexer, "%s", error);
+          free (error);
          goto error;
        }
       lex_get (lexer);
index ad25f400aaeac75924981210cfd190db4161f907..cf493391e4d9ccdf5729a6d974ce1056ce8bb774 100644 (file)
@@ -95,12 +95,22 @@ try_to_sequence (struct lexer *lexer, const struct dictionary *dict,
   /* Check that the first and last tokens are suitable as
      variable names.  */
   const char *s0 = lex_tokcstr (lexer);
-  if (!id_is_valid (s0, dict_get_encoding (dict), true))
-    return NULL;
+  char *error = id_is_valid__ (s0, dict_get_encoding (dict));
+  if (error)
+    {
+      lex_error (lexer, "%s", error);
+      free (error);
+      return NULL;
+    }
 
   const char *s1 = lex_next_tokcstr (lexer, 2);
-  if (!id_is_valid (s1, dict_get_encoding (dict), true))
-    return NULL;
+  error = id_is_valid__ (s1, dict_get_encoding (dict));
+  if (error)
+    {
+      lex_next_error (lexer, 2, 2, "%s", error);
+      free (error);
+      return NULL;
+    }
 
   int x0 = strcspn (s0, "0123456789");
   int x1 = strcspn (s1, "0123456789");
@@ -211,8 +221,16 @@ parse_dict_rename (struct lexer *lexer, struct dictionary *dict,
           if (n_newvars >= n_oldvars)
             break;
           const char *new_name = lex_tokcstr (lexer);
-          if (!relax && ! id_is_plausible (new_name, true))
-            goto fail;
+          if (!relax)
+            {
+              char *error = id_is_plausible__ (new_name);
+              if (error)
+                {
+                  lex_error (lexer, "%s", error);
+                  free (error);
+                  goto fail;
+                }
+            }
 
           if (!check_rename (dict, var_get_name (oldvars[n_newvars]), new_name))
             goto fail;
index 88832fd501f641ebcc041c1558fa3d214047c454..954314ef4fb07339f599e8f6974582e5b1cf00c3 100644 (file)
@@ -87,12 +87,16 @@ static char *
 parse_attribute_name (struct lexer *lexer, const char *dict_encoding,
                       size_t *index)
 {
-  char *name;
-
-  if (!lex_force_id (lexer)
-      || !id_is_valid (lex_tokcstr (lexer), dict_encoding, true))
+  if (!lex_force_id (lexer))
     return NULL;
-  name = xstrdup (lex_tokcstr (lexer));
+  char *error = id_is_valid__ (lex_tokcstr (lexer), dict_encoding);
+  if (error)
+    {
+      lex_error (lexer, "%s", error);
+      free (error);
+      return NULL;
+    }
+  char *name = xstrdup (lex_tokcstr (lexer));
   lex_get (lexer);
 
   if (lex_match (lexer, T_LBRACK))
index 0ea5cb8c82af87cb3096ad012c45fc8c2dab726d..1f281221a258c6e49d3a0183ccb74c01321008fb 100644 (file)
@@ -92,10 +92,16 @@ parse_group (struct lexer *lexer, struct dictionary *dict,
     {
       if (lex_match_id (lexer, "NAME"))
         {
-          if (!lex_force_match (lexer, T_EQUALS) || !lex_force_id (lexer)
-              || !mrset_is_valid_name (lex_tokcstr (lexer),
-                                       dict_get_encoding (dict), true))
+          if (!lex_force_match (lexer, T_EQUALS) || !lex_force_id (lexer))
             goto error;
+          char *error = mrset_is_valid_name__ (lex_tokcstr (lexer),
+                                               dict_get_encoding (dict));
+          if (error)
+            {
+              lex_error (lexer, "%s", error);
+              free (error);
+              goto error;
+            }
 
           free (mrset->name);
           mrset->name = xstrdup (lex_tokcstr (lexer));
index 45c352579ca41817c0102cf5f53825809fc40d12..4ba4ddd4e0a35e9c8459d66ef6614e508f39d795 100644 (file)
@@ -836,7 +836,7 @@ recode_strings (struct pool *pool,
           ss_rtrim (&utf8, ss_cstr (" "));
           utf8.string[utf8.length] = '\0';
 
-          if (ids[i] && !id_is_plausible (utf8.string, false))
+          if (ids[i] && !id_is_plausible (utf8.string))
             error = EINVAL;
         }
 
index 02687e51a9f71d3095bf82b7040ca69cb1122dfe..fe1ab99e145227b2e808d23920ff7ae9c50ed7f9 100644 (file)
@@ -51,9 +51,15 @@ cmd_vector (struct lexer *lexer, struct dataset *ds)
       size_t n_vectors, allocated_vectors;
 
       /* Get the name(s) of the new vector(s). */
-      if (!lex_force_id (lexer)
-          || !dict_id_is_valid (dict, lex_tokcstr (lexer), true))
+      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;
       n_vectors = allocated_vectors = 0;
@@ -111,17 +117,10 @@ 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 n_vars;
-
-          size_t i;
-
-          n_vars = 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) && n_vars == 0)
@@ -145,6 +144,7 @@ cmd_vector (struct lexer *lexer, struct dataset *ds)
                 }
               lex_match (lexer, T_COMMA);
             }
+          int end_ofs = lex_ofs (lexer) - 1;
           if (n_vars == 0)
             {
               lex_error (lexer, _("Syntax error expecting vector length."));
@@ -153,20 +153,25 @@ cmd_vector (struct lexer *lexer, struct dataset *ds)
 
          /* Check that none of the variables exist and that their names are
              not excessively long. */
-          for (i = 0; i < n_vectors; i++)
+          for (size_t i = 0; i < n_vectors; i++)
            {
               int j;
              for (j = 0; j < n_vars; j++)
                {
                   char *name = xasprintf ("%s%d", vectors[i], j + 1);
-                  if (!dict_id_is_valid (dict, name, true))
+                  char *error = dict_id_is_valid__ (dict, name);
+                  if (error)
                     {
+                      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;
                    }
@@ -175,13 +180,12 @@ cmd_vector (struct lexer *lexer, struct dataset *ds)
            }
 
          /* Finally create the variables and vectors. */
-          vars = pool_nmalloc (pool, n_vars, sizeof *vars);
-          for (i = 0; i < n_vectors; 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 < n_vars; j++)
+             for (size_t j = 0; j < n_vars; j++)
                {
-                  char *name = xasprintf ("%s%d", vectors[i], j + 1);
+                  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);
index 7d30a2ad9253f0f1cc81326f139199d9ab85fde8..f444f15e2beb0c28ccc708af69463e64a3ebdd03 100644 (file)
@@ -437,8 +437,13 @@ parse_DATA_LIST_var (struct lexer *lexer, const struct dictionary *d)
       lex_error (lexer, ("Syntax error expecting variable name."));
       return NULL;
     }
-  if (!dict_id_is_valid (d, lex_tokcstr (lexer), true))
-    return NULL;
+  char *error = dict_id_is_valid__ (d, lex_tokcstr (lexer));
+  if (error)
+    {
+      lex_error (lexer, "%s", error);
+      free (error);
+      return NULL;
+    }
 
   char *name = xstrdup (lex_tokcstr (lexer));
   lex_get (lexer);
index 113d565367c894baea9ad3fae275043f497c4e45..cf11e2312c0915409b80f12194c24f42875ee8d0 100644 (file)
@@ -281,7 +281,7 @@ make_new_var (struct dictionary *dict, const char *name_)
 
   /* Use the mangled name, if it is available, or add numeric
      extensions until we find one that is. */
-  if (!id_is_plausible (name, false) || !dict_create_var (dict, name, 0))
+  if (!id_is_plausible (name) || !dict_create_var (dict, name, 0))
     {
       int len = strlen (name);
       int i;
@@ -292,7 +292,7 @@ make_new_var (struct dictionary *dict, const char *name_)
           strncpy (n, name, ofs);
           sprintf (&n[ofs], "%d", i);
 
-          if (id_is_plausible (n, false) && dict_create_var (dict, n, 0))
+          if (id_is_plausible (n) && dict_create_var (dict, n, 0))
             break;
         }
     }
index ba6a1402074926f8aefc84e4aadd86b0c6729c8c..7c8d6519d18270b01d8b50c317d14e424c885351 100644 (file)
@@ -6135,10 +6135,15 @@ save_file_open (struct save_file *sf, gsl_matrix *m,
           for (size_t i = 0; i < nv.size; i++)
             {
               char *name = trimmed_string (gsl_vector_get (&nv, i));
-              if (dict_id_is_valid (dict, name, true))
+              char *error = dict_id_is_valid__ (dict, name);
+              if (!error)
                 string_array_append_nocopy (&names, name);
               else
-                ok = false;
+                {
+                  msg_at (SE, save_location, "%s", error);
+                  free (error);
+                  ok = false;
+                }
             }
         }
       gsl_matrix_free (nm);
index 215a1d3e5811cbe02a3c94589fb8d81d5cec178a..70d3b4934551d7576c50f7383b1735e620c66ce8 100644 (file)
@@ -454,7 +454,7 @@ psppire_dict_set_name (PsppireDict* d, gint idx, const gchar *name)
   g_assert (d);
   g_assert (PSPPIRE_IS_DICT (d));
 
-  if (! dict_id_is_valid (d->dict, name, false))
+  if (! dict_id_is_valid (d->dict, name))
     return FALSE;
 
   if (idx < dict_get_n_vars (d->dict))
@@ -550,26 +550,15 @@ psppire_dict_clear (PsppireDict *d)
 
 /* Return true if NAME would be a valid name of a variable to add to the
    dictionary.  False otherwise.
-   If REPORT is true, then invalid names will be reported as such as errors
 */
 gboolean
 psppire_dict_check_name (const PsppireDict *dict,
-                        const gchar *name, gboolean report)
+                        const gchar *name)
 {
-  if (! dict_id_is_valid (dict->dict, name, report))
-    return FALSE;
-
-  if (psppire_dict_lookup_var (dict, name))
-    {
-      if (report)
-       msg (ME, _("Duplicate variable name."));
-      return FALSE;
-    }
-
-  return TRUE;
+  return (dict_id_is_valid (dict->dict, name)
+          && !psppire_dict_lookup_var (dict, name));
 }
 
-
 gint
 psppire_dict_get_next_value_idx (const PsppireDict *dict)
 {
@@ -891,7 +880,7 @@ gboolean
 psppire_dict_rename_var (PsppireDict *dict, struct variable *v,
                         const gchar *name)
 {
-  if (! dict_id_is_valid (dict->dict, name, false))
+  if (! dict_id_is_valid (dict->dict, name))
     return FALSE;
 
   /* Make sure no other variable has this name */
index 76c3aa42e88a195f9528720e41d80c11cbf49c47..e5f803296501f1cc7ba9449e7b153eb27282c313 100644 (file)
@@ -107,8 +107,7 @@ void psppire_dict_delete_variables (PsppireDict *d, gint first, gint n);
 struct variable *psppire_dict_insert_variable (PsppireDict *d, gint idx,
                                                const gchar *name);
 
-gboolean psppire_dict_check_name (const PsppireDict *dict,
-                             const gchar *name, gboolean report);
+gboolean psppire_dict_check_name (const PsppireDict *, const gchar *name);
 
 bool psppire_dict_generate_name (const PsppireDict *, char *name, size_t size);
 
index 486d85c4ca2dd0aa37f1cf6526cc2dbd9ad5bb05..573e66e4cc8206ea0a2b5f8fb48dca9936537c7c 100644 (file)
@@ -342,7 +342,7 @@ change_var_property (PsppireVariableSheet *var_sheet, gint col, gint row, const
     case DICT_TVM_COL_NAME:
       {
        const char *name = g_value_get_string (value);
-       if (psppire_dict_check_name (dict, name, FALSE))
+       if (psppire_dict_check_name (dict, name))
          dict_rename_var (dict->dict, var, g_value_get_string (value));
       }
       break;
index bddbbd191905c572c979fcde48fff7585fda7359..b72803c19e509279841ae413cd55c6c0d91acba4 100644 (file)
@@ -198,8 +198,10 @@ AT_DATA([mrsets.sps],
   [DEFINE_MRSETS_DATA
 MRSETS /MCGROUP NAME=x.
 ])
-AT_CHECK([pspp -O format=csv mrsets.sps], [1],
-  [mrsets.sps:6: error: MRSETS: x is not a valid name for a multiple response set.  Multiple response set names must begin with `$'.
+AT_CHECK([pspp -O format=csv mrsets.sps], [1], [dnl
+"mrsets.sps:6.22: error: MRSETS: x is not a valid name for a multiple response set.  Multiple response set names must begin with `$'.
+    6 | MRSETS /MCGROUP NAME=x.
+      |                      ^"
 ])
 AT_CLEANUP