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;
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
/* 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);
/* 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);
#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
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));
}
}
}
-/* 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:
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)
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 *);
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;
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);
}
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 "
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);
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,
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);
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;
}
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);
/* 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");
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;
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))
{
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));
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;
}
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;
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)
}
lex_match (lexer, T_COMMA);
}
+ int end_ofs = lex_ofs (lexer) - 1;
if (n_vars == 0)
{
lex_error (lexer, _("Syntax error expecting vector length."));
/* 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;
}
}
/* 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);
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);
/* 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;
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;
}
}
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);
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))
/* 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)
{
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 */
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);
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;
[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