static void destroy_spreadsheet_read_info (struct spreadsheet_read_options *);
-static int parse_get_txt (struct lexer *lexer, struct dataset *);
-static int parse_get_psql (struct lexer *lexer, struct dataset *);
+static int parse_get_txt (struct lexer *, struct dataset *);
+static int parse_get_psql (struct lexer *, struct dataset *);
+static int parse_get_spreadsheet (struct lexer *, struct dataset *,
+ struct spreadsheet *(*probe)(
+ const char *filename, bool report_errors));
int
cmd_get_data (struct lexer *lexer, struct dataset *ds)
{
- char *tok = NULL;
- struct spreadsheet_read_options opts;
-
- opts.sheet_name = NULL;
- opts.sheet_index = -1;
- opts.cell_range = NULL;
- opts.read_names = false;
- opts.asw = -1;
-
- if (! lex_force_match (lexer, T_SLASH))
- goto error;
-
- if (!lex_force_match_id (lexer, "TYPE"))
- goto error;
-
- if (!lex_force_match (lexer, T_EQUALS))
- goto error;
-
- const char *s = lex_tokcstr (lexer);
-
- if (s)
- tok = strdup (s);
+ if (!lex_force_match_phrase (lexer, "/TYPE="))
+ return CMD_FAILURE;
if (lex_match_id (lexer, "TXT"))
- {
- free (tok);
- return parse_get_txt (lexer, ds);
- }
+ return parse_get_txt (lexer, ds);
else if (lex_match_id (lexer, "PSQL"))
+ return parse_get_psql (lexer, ds);
+ else if (lex_match_id (lexer, "GNM"))
+ return parse_get_spreadsheet (lexer, ds, gnumeric_probe);
+ else if (lex_match_id (lexer, "ODS"))
+ return parse_get_spreadsheet (lexer, ds, ods_probe);
+ else
{
- free (tok);
- return parse_get_psql (lexer, ds);
+ lex_error_expecting (lexer, "TXT", "PSQL", "GNM", "ODS");
+ return CMD_FAILURE;
}
- else if (lex_match_id (lexer, "GNM") ||
- lex_match_id (lexer, "ODS"))
- {
- char *filename = NULL;
- if (!parse_spreadsheet (lexer, &filename, &opts))
- goto error;
+}
- struct spreadsheet *spreadsheet = NULL;
- if (0 == strncasecmp (tok, "GNM", 3))
- spreadsheet = gnumeric_probe (filename, true);
- else if (0 == strncasecmp (tok, "ODS", 3))
- spreadsheet = ods_probe (filename, true);
+static int
+parse_get_spreadsheet (struct lexer *lexer, struct dataset *ds,
+ struct spreadsheet *(*probe)(
+ const char *filename, bool report_errors))
+{
+ struct spreadsheet_read_options opts;
+ char *filename;
+ if (!parse_spreadsheet (lexer, &filename, &opts))
+ return CMD_FAILURE;
- if (spreadsheet == NULL)
- {
- msg (SE, _("error reading file `%s'"), filename);
- free (filename);
- goto error;
- }
- free (filename);
+ bool ok = false;
+ struct spreadsheet *spreadsheet = probe (filename, true);
+ if (!spreadsheet)
+ {
+ msg (SE, _("error reading file `%s'"), filename);
+ goto done;
+ }
- struct casereader *reader = spreadsheet_make_reader (spreadsheet, &opts);
- if (reader)
- {
- dataset_set_dict (ds, dict_clone (spreadsheet->dict));
- dataset_set_source (ds, reader);
- free (tok);
- destroy_spreadsheet_read_info (&opts);
- spreadsheet_unref (spreadsheet);
- return CMD_SUCCESS;
- }
- spreadsheet_unref (spreadsheet);
+ struct casereader *reader = spreadsheet_make_reader (spreadsheet, &opts);
+ if (reader)
+ {
+ dataset_set_dict (ds, dict_clone (spreadsheet->dict));
+ dataset_set_source (ds, reader);
+ ok = true;
}
- else
- lex_error_expecting (lexer, "TXT", "PSQL", "GNM", "ODS");
+ spreadsheet_unref (spreadsheet);
- error:
+done:
+ free (filename);
destroy_spreadsheet_read_info (&opts);
- free (tok);
- return CMD_FAILURE;
+ return ok ? CMD_SUCCESS : CMD_FAILURE;
}
static int
parse_get_psql (struct lexer *lexer, struct dataset *ds)
{
- struct psql_read_info psql;
- psql.allow_clear = false;
- psql.conninfo = NULL;
- psql.str_width = -1;
- psql.bsize = -1;
- ds_init_empty (&psql.sql);
-
- if (! lex_force_match (lexer, T_SLASH))
- goto error;
-
- if (!lex_force_match_id (lexer, "CONNECT"))
- goto error;
-
- if (! lex_force_match (lexer, T_EQUALS))
- goto error;
-
- if (!lex_force_string (lexer))
- goto error;
+ if (!lex_force_match_phrase (lexer, "/CONNECT=") || !lex_force_string (lexer))
+ return CMD_FAILURE;
- psql.conninfo = ss_xstrdup (lex_tokss (lexer));
+ struct psql_read_info psql = {
+ .str_width = -1,
+ .bsize = -1,
+ .conninfo = ss_xstrdup (lex_tokss (lexer)),
+ };
+ bool ok = false;
lex_get (lexer);
if (lex_match_id (lexer, "ASSUMEDSTRWIDTH"))
{
lex_match (lexer, T_EQUALS);
- if (lex_force_int_range (lexer, "ASSUMEDSTRWIDTH", 1, 32767))
- {
- psql.str_width = lex_integer (lexer);
- lex_get (lexer);
- }
+ if (!lex_force_int_range (lexer, "ASSUMEDSTRWIDTH", 1, 32767))
+ goto done;
+ psql.str_width = lex_integer (lexer);
+ lex_get (lexer);
}
else if (lex_match_id (lexer, "BSIZE"))
{
lex_match (lexer, T_EQUALS);
- if (lex_force_int_range (lexer, "BSIZE", 1, INT_MAX))
- {
- psql.bsize = lex_integer (lexer);
- lex_get (lexer);
- }
+ if (!lex_force_int_range (lexer, "BSIZE", 1, INT_MAX))
+ goto done;
+ psql.bsize = lex_integer (lexer);
+ lex_get (lexer);
}
else if (lex_match_id (lexer, "UNENCRYPTED"))
- {
- psql.allow_clear = true;
- }
+ psql.allow_clear = true;
else if (lex_match_id (lexer, "SQL"))
{
lex_match (lexer, T_EQUALS);
- if (! lex_force_string (lexer))
- goto error;
+ if (!lex_force_string (lexer))
+ goto done;
- ds_put_substring (&psql.sql, lex_tokss (lexer));
+ free (psql.sql);
+ psql.sql = ss_xstrdup (lex_tokss (lexer));
lex_get (lexer);
}
}
- {
- struct dictionary *dict = NULL;
- struct casereader *reader = psql_open_reader (&psql, &dict);
-
- if (reader)
- {
- dataset_set_dict (ds, dict);
- dataset_set_source (ds, reader);
- }
- }
-
- ds_destroy (&psql.sql);
- free (psql.conninfo);
- return CMD_SUCCESS;
-
- error:
+ struct dictionary *dict = NULL;
+ struct casereader *reader = psql_open_reader (&psql, &dict);
+ if (reader)
+ {
+ dataset_set_dict (ds, dict);
+ dataset_set_source (ds, reader);
+ }
- ds_destroy (&psql.sql);
+ done:
free (psql.conninfo);
+ free (psql.sql);
- return CMD_FAILURE;
+ return ok ? CMD_SUCCESS : CMD_FAILURE;
}
static bool
parse_spreadsheet (struct lexer *lexer, char **filename,
struct spreadsheet_read_options *opts)
{
- opts->sheet_index = 1;
- opts->sheet_name = NULL;
- opts->cell_range = NULL;
- opts->read_names = true;
- opts->asw = -1;
-
- if (! lex_force_match (lexer, T_SLASH))
+ *opts = (struct spreadsheet_read_options) {
+ .sheet_index = 1,
+ .read_names = true,
+ .asw = -1,
+ };
+ *filename = NULL;
+
+ if (!lex_force_match_phrase (lexer, "/FILE=") || !lex_force_string (lexer))
goto error;
- if (!lex_force_match_id (lexer, "FILE"))
- goto error;
-
- if (! lex_force_match (lexer, T_EQUALS))
- goto error;
-
- if (!lex_force_string (lexer))
- goto error;
-
- *filename = utf8_to_filename (lex_tokcstr (lexer));
-
+ *filename = utf8_to_filename (lex_tokcstr (lexer));
lex_get (lexer);
while (lex_match (lexer, T_SLASH))
if (lex_match_id (lexer, "ASSUMEDSTRWIDTH"))
{
lex_match (lexer, T_EQUALS);
- if (lex_force_int_range (lexer, "ASSUMEDSTRWIDTH", 1, 32767))
- {
- opts->asw = lex_integer (lexer);
- lex_get (lexer);
- }
+ if (!lex_force_int_range (lexer, "ASSUMEDSTRWIDTH", 1, 32767))
+ goto error;
+ opts->asw = lex_integer (lexer);
+ lex_get (lexer);
}
else if (lex_match_id (lexer, "SHEET"))
{
lex_match (lexer, T_EQUALS);
if (lex_match_id (lexer, "NAME"))
{
- if (! lex_force_string (lexer))
+ if (!lex_force_string (lexer))
goto error;
opts->sheet_name = ss_xstrdup (lex_tokss (lexer));
lex_match (lexer, T_EQUALS);
if (lex_match_id (lexer, "FULL"))
- {
- opts->cell_range = NULL;
- }
+ opts->cell_range = NULL;
else if (lex_match_id (lexer, "RANGE"))
{
- if (! lex_force_string (lexer))
+ if (!lex_force_string (lexer))
goto error;
opts->cell_range = ss_xstrdup (lex_tokss (lexer));
lex_match (lexer, T_EQUALS);
if (lex_match_id (lexer, "ON"))
- {
- opts->read_names = true;
- }
+ opts->read_names = true;
else if (lex_match_id (lexer, "OFF"))
- {
- opts->read_names = false;
- }
+ opts->read_names = false;
else
{
lex_error_expecting (lexer, "ON", "OFF");
}
else
{
- lex_error (lexer, NULL);
+ lex_error_expecting (lexer, "ASSUMEDSTRWIDTH", "SHEET", "CELLRANGE",
+ "READNAMES");
goto error;
}
}
return true;
error:
+ destroy_spreadsheet_read_info (opts);
+ free (*filename);
return false;
}
static bool
-set_type (struct data_parser *parser, const char *subcommand,
- enum data_parser_type type, bool *has_type)
+set_type (struct lexer *lexer, struct data_parser *parser,
+ enum data_parser_type type,
+ int type_start, int type_end, int *type_startp, int *type_endp)
{
- if (!*has_type)
+ if (!*type_startp)
{
data_parser_set_type (parser, type);
- *has_type = true;
+ *type_startp = type_start;
+ *type_endp = type_end;
}
else if (type != data_parser_get_type (parser))
{
- msg (SE, _("%s is allowed only with %s arrangement, but %s arrangement "
- "was stated or implied earlier in this command."),
- subcommand,
- type == DP_FIXED ? "FIXED" : "DELIMITED",
- type == DP_FIXED ? "DELIMITED" : "FIXED");
+ msg (SE, _("FIXED and DELIMITED arrangements are mutually exclusive."));
+ lex_ofs_msg (lexer, SN, type_start, type_end,
+ _("This syntax requires %s arrangement."),
+ type == DP_FIXED ? "FIXED" : "DELIMITED");
+ lex_ofs_msg (lexer, SN, *type_startp, *type_endp,
+ _("This syntax requires %s arrangement."),
+ type == DP_FIXED ? "DELIMITED" : "FIXED");
return false;
}
return true;
static int
parse_get_txt (struct lexer *lexer, struct dataset *ds)
{
- struct data_parser *parser = NULL;
struct dictionary *dict = dict_create (get_default_encoding ());
+ struct data_parser *parser = data_parser_create ();
struct file_handle *fh = NULL;
- struct dfm_reader *reader = NULL;
char *encoding = NULL;
char *name = NULL;
- int record;
- enum data_parser_type type;
- bool has_type;
-
- if (! lex_force_match (lexer, T_SLASH))
- goto error;
-
- if (!lex_force_match_id (lexer, "FILE"))
- goto error;
- if (! lex_force_match (lexer, T_EQUALS))
+ if (!lex_force_match_phrase (lexer, "/FILE="))
goto error;
fh = fh_parse (lexer, FH_REF_FILE | FH_REF_INLINE, NULL);
if (fh == NULL)
goto error;
- parser = data_parser_create ();
- has_type = false;
+ int type_start = 0, type_end = 0;
data_parser_set_type (parser, DP_DELIMITED);
data_parser_set_span (parser, false);
data_parser_set_quotes (parser, ss_empty ());
lex_match (lexer, T_EQUALS);
if (lex_match_id (lexer, "FIXED"))
- ok = set_type (parser, "ARRANGEMENT=FIXED", DP_FIXED, &has_type);
+ ok = set_type (lexer, parser, DP_FIXED,
+ lex_ofs (lexer) - 3, lex_ofs (lexer) - 1,
+ &type_start, &type_end);
else if (lex_match_id (lexer, "DELIMITED"))
- ok = set_type (parser, "ARRANGEMENT=DELIMITED",
- DP_DELIMITED, &has_type);
+ ok = set_type (lexer, parser, DP_DELIMITED,
+ lex_ofs (lexer) - 3, lex_ofs (lexer) - 1,
+ &type_start, &type_end);
else
{
lex_error_expecting (lexer, "FIXED", "DELIMITED");
}
else if (lex_match_id_n (lexer, "DELCASE", 4))
{
- if (!set_type (parser, "DELCASE", DP_DELIMITED, &has_type))
+ if (!set_type (lexer, parser, DP_DELIMITED,
+ lex_ofs (lexer) - 1, lex_ofs (lexer) - 1,
+ &type_start, &type_end))
goto error;
lex_match (lexer, T_EQUALS);
if (lex_match_id (lexer, "LINE"))
}
else if (lex_match_id (lexer, "FIXCASE"))
{
- if (!set_type (parser, "FIXCASE", DP_FIXED, &has_type))
+ if (!set_type (lexer, parser, DP_FIXED,
+ lex_ofs (lexer) - 1, lex_ofs (lexer) - 1,
+ &type_start, &type_end))
goto error;
lex_match (lexer, T_EQUALS);
if (!lex_force_int_range (lexer, "FIXCASE", 1, INT_MAX))
}
else if (lex_match_id_n (lexer, "DELIMITERS", 4))
{
- struct string hard_seps = DS_EMPTY_INITIALIZER;
- const char *soft_seps = "";
- struct substring s;
- int c;
-
- if (!set_type (parser, "DELIMITERS", DP_DELIMITED, &has_type))
+ if (!set_type (lexer, parser, DP_DELIMITED,
+ lex_ofs (lexer) - 1, lex_ofs (lexer) - 1,
+ &type_start, &type_end))
goto error;
lex_match (lexer, T_EQUALS);
goto error;
/* XXX should support multibyte UTF-8 characters */
- s = lex_tokss (lexer);
+ struct substring s = lex_tokss (lexer);
+ struct string hard_seps = DS_EMPTY_INITIALIZER;
+ const char *soft_seps = "";
if (ss_match_string (&s, ss_cstr ("\\t")))
ds_put_cstr (&hard_seps, "\t");
if (ss_match_string (&s, ss_cstr ("\\\\")))
ds_put_cstr (&hard_seps, "\\");
+ int c;
while ((c = ss_get_byte (&s)) != EOF)
if (c == ' ')
soft_seps = " ";
}
else if (lex_match_id (lexer, "QUALIFIERS"))
{
- if (!set_type (parser, "QUALIFIERS", DP_DELIMITED, &has_type))
+ if (!set_type (lexer, parser, DP_DELIMITED,
+ lex_ofs (lexer) - 1, lex_ofs (lexer) - 1,
+ &type_start, &type_end))
goto error;
lex_match (lexer, T_EQUALS);
}
lex_match (lexer, T_EQUALS);
- record = 1;
- type = data_parser_get_type (parser);
+ int record = 1;
+ enum data_parser_type type = data_parser_get_type (parser);
do
{
- struct fmt_spec input, output;
- struct variable *v;
- int fc, lc;
-
while (type == DP_FIXED && lex_match (lexer, T_SLASH))
{
if (!lex_force_int_range (lexer, NULL, record,
goto error;
}
lex_get (lexer);
+
+ struct fmt_spec input, output;
+ int fc, lc;
if (type == DP_DELIMITED)
{
if (!parse_format_specifier (lexer, &input))
error = fmt_check_input__ (&input);
if (error)
{
- lex_next_error (lexer, start_ofs, end_ofs, "%s", error);
+ lex_ofs_error (lexer, start_ofs, end_ofs, "%s", error);
free (error);
goto error;
}
error = fmt_check_output__ (&output);
if (error)
{
- lex_next_error (lexer, start_ofs, end_ofs, "%s", error);
+ lex_ofs_error (lexer, start_ofs, end_ofs, "%s", error);
free (error);
goto error;
}
output = fmt_for_output_from_input (&input,
settings_get_fmt_settings ());
}
- v = dict_create_var (dict, name, fmt_var_width (&input));
- if (v == NULL)
+ struct variable *v = dict_create_var (dict, name, fmt_var_width (&input));
+ if (!v)
{
lex_ofs_error (lexer, name_ofs, name_ofs,
_("%s is a duplicate variable name."), name);
}
while (lex_token (lexer) != T_ENDCMD);
- reader = dfm_open_reader (fh, lexer, encoding);
- if (reader == NULL)
+ struct dfm_reader *reader = dfm_open_reader (fh, lexer, encoding);
+ if (!reader)
goto error;
data_parser_make_active_file (parser, ds, reader, dict, NULL, NULL);
return CMD_CASCADING_FAILURE;
}
-
static void
destroy_spreadsheet_read_info (struct spreadsheet_read_options *opts)
{
--- /dev/null
+AT_BANNER([GET DATA])
+
+AT_SETUP([GET DATA syntax errors])
+AT_DATA([get-data.sps], [dnl
+GET DATA **.
+GET DATA / **.
+GET DATA /TYPE **.
+
+GET DATA /TYPE=TXT **.
+GET DATA /TYPE=TXT/ **.
+GET DATA /TYPE=TXT/FILE **.
+GET DATA /TYPE=TXT/FILE='x.txt' **.
+GET DATA /TYPE=TXT/FILE='x.txt' /ENCODING=**.
+GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=**.
+GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=FIXED /ARRANGEMENT=DELIMITED.
+GET DATA /TYPE=TXT/FILE='x.txt' /FIRSTCASE=**.
+GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=FIXED /DELCASE=LINE.
+GET DATA /TYPE=TXT/FILE='x.txt' /DELCASE=VARIABLES **.
+GET DATA /TYPE=TXT/FILE='x.txt' /DELCASE=**.
+GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=DELIMITED /FIXCASE=1.
+GET DATA /TYPE=TXT/FILE='x.txt' /FIXCASE=**.
+GET DATA /TYPE=TXT/FILE='x.txt' /IMPORTCASES=FIRST **.
+GET DATA /TYPE=TXT/FILE='x.txt' /IMPORTCASES=PERCENT **.
+GET DATA /TYPE=TXT/FILE='x.txt' /IMPORTCASES=ALL.
+GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=FIXED /DELIMITERS=' '.
+GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=FIXED /QUALIFIER='"'.
+GET DATA /TYPE=TXT/FILE='x.txt' /QUALIFIER='"' + "'".
+GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=FIXED /VARIABLES / **.
+GET DATA /TYPE=TXT/FILE='x.txt' /VARIABLES **.
+GET DATA /TYPE=TXT/FILE='x.txt' /VARIABLES a_very_long_name_that_exceeds_the_64_byte_limit_for_variable_names.
+GET DATA /TYPE=TXT/FILE='x.txt' /VARIABLES x **.
+GET DATA /TYPE=TXT/FILE='x.txt' /VARIABLES x F1.2.
+GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=FIXED /VARIABLES x **.
+GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=FIXED /VARIABLES x 1-5 **.
+GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=FIXED /VARIABLES x 1-5 FOO.
+GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=FIXED /VARIABLES x 1-5 DATE.
+GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=FIXED /VARIABLES x 1-5 DOLLAR1.2.
+GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=FIXED /VARIABLES x 1-5 F x 6-10 F.
+
+GET DATA /TYPE=PSQL **.
+GET DATA /TYPE=PSQL/ **.
+GET DATA /TYPE=PSQL/CONNECT **.
+GET DATA /TYPE=PSQL/CONNECT='db'/ASSUMEDSTRWIDTH=**.
+GET DATA /TYPE=PSQL/CONNECT='db'/BSIZE=**.
+GET DATA /TYPE=PSQL/CONNECT='db'/SQL=**.
+
+GET DATA /TYPE=GNM **.
+GET DATA /TYPE=GNM/ **.
+GET DATA /TYPE=GNM/FILE **.
+GET DATA /TYPE=GNM/FILE= **.
+GET DATA /TYPE=GNM/FILE='x.gnumeric'/ASSUMEDSTRWIDTH=**.
+GET DATA /TYPE=GNM/FILE='x.gnumeric'/SHEET=NAME **.
+GET DATA /TYPE=GNM/FILE='x.gnumeric'/SHEET=INDEX **.
+GET DATA /TYPE=GNM/FILE='x.gnumeric'/SHEET=**.
+GET DATA /TYPE=GNM/FILE='x.gnumeric'/CELLRANGE=RANGE **.
+GET DATA /TYPE=GNM/FILE='x.gnumeric'/CELLRANGE=**.
+GET DATA /TYPE=GNM/FILE='x.gnumeric'/READNAMES=**.
+GET DATA /TYPE=GNM/FILE='x.gnumeric'/ **.
+])
+AT_DATA([insert.sps], [dnl
+INSERT FILE='get-data.sps' ERROR=IGNORE.
+])
+AT_CHECK([pspp -x compatible --testing-mode -O format=csv insert.sps], [1], [dnl
+"get-data.sps:1.10-1.11: error: GET DATA: Syntax error expecting `/TYPE='.
+ 1 | GET DATA **.
+ | ^~"
+
+"get-data.sps:2.10-2.13: error: GET DATA: Syntax error expecting `/TYPE='.
+ 2 | GET DATA / **.
+ | ^~~~"
+
+"get-data.sps:3.10-3.17: error: GET DATA: Syntax error expecting `/TYPE='.
+ 3 | GET DATA /TYPE **.
+ | ^~~~~~~~"
+
+"get-data.sps:5.20-5.21: error: GET DATA: Syntax error expecting `/FILE='.
+ 5 | GET DATA /TYPE=TXT **.
+ | ^~"
+
+"get-data.sps:6.19-6.22: error: GET DATA: Syntax error expecting `/FILE='.
+ 6 | GET DATA /TYPE=TXT/ **.
+ | ^~~~"
+
+"get-data.sps:7.19-7.26: error: GET DATA: Syntax error expecting `/FILE='.
+ 7 | GET DATA /TYPE=TXT/FILE **.
+ | ^~~~~~~~"
+
+"get-data.sps:8.33-8.34: error: GET DATA: Syntax error expecting `/'.
+ 8 | GET DATA /TYPE=TXT/FILE='x.txt' **.
+ | ^~"
+
+"get-data.sps:9.43-9.44: error: GET DATA: Syntax error expecting string.
+ 9 | GET DATA /TYPE=TXT/FILE='x.txt' /ENCODING=**.
+ | ^~"
+
+"get-data.sps:10.46-10.47: error: GET DATA: Syntax error expecting FIXED or DELIMITED.
+ 10 | GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=**.
+ | ^~"
+
+get-data.sps:11: error: GET DATA: FIXED and DELIMITED arrangements are mutually exclusive.
+
+"get-data.sps:11.53-11.73: note: GET DATA: This syntax requires DELIMITED arrangement.
+ 11 | GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=FIXED /ARRANGEMENT=DELIMITED.
+ | ^~~~~~~~~~~~~~~~~~~~~"
+
+"get-data.sps:11.34-11.50: note: GET DATA: This syntax requires FIXED arrangement.
+ 11 | GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=FIXED /ARRANGEMENT=DELIMITED.
+ | ^~~~~~~~~~~~~~~~~"
+
+"get-data.sps:12.44-12.45: error: GET DATA: Syntax error expecting positive integer for FIRSTCASE.
+ 12 | GET DATA /TYPE=TXT/FILE='x.txt' /FIRSTCASE=**.
+ | ^~"
+
+get-data.sps:13: error: GET DATA: FIXED and DELIMITED arrangements are mutually exclusive.
+
+"get-data.sps:13.53-13.59: note: GET DATA: This syntax requires DELIMITED arrangement.
+ 13 | GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=FIXED /DELCASE=LINE.
+ | ^~~~~~~"
+
+"get-data.sps:13.34-13.50: note: GET DATA: This syntax requires FIXED arrangement.
+ 13 | GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=FIXED /DELCASE=LINE.
+ | ^~~~~~~~~~~~~~~~~"
+
+"get-data.sps:14.52-14.53: error: GET DATA: Syntax error expecting integer.
+ 14 | GET DATA /TYPE=TXT/FILE='x.txt' /DELCASE=VARIABLES **.
+ | ^~"
+
+"get-data.sps:15.42-15.43: error: GET DATA: Syntax error expecting LINE or VARIABLES.
+ 15 | GET DATA /TYPE=TXT/FILE='x.txt' /DELCASE=**.
+ | ^~"
+
+get-data.sps:16: error: GET DATA: FIXED and DELIMITED arrangements are mutually exclusive.
+
+"get-data.sps:16.57-16.63: note: GET DATA: This syntax requires FIXED arrangement.
+ 16 | GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=DELIMITED /FIXCASE=1.
+ | ^~~~~~~"
+
+"get-data.sps:16.34-16.54: note: GET DATA: This syntax requires DELIMITED arrangement.
+ 16 | GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=DELIMITED /FIXCASE=1.
+ | ^~~~~~~~~~~~~~~~~~~~~"
+
+"get-data.sps:17.42-17.43: error: GET DATA: Syntax error expecting positive integer for FIXCASE.
+ 17 | GET DATA /TYPE=TXT/FILE='x.txt' /FIXCASE=**.
+ | ^~"
+
+"get-data.sps:18.52-18.53: error: GET DATA: Syntax error expecting integer.
+ 18 | GET DATA /TYPE=TXT/FILE='x.txt' /IMPORTCASES=FIRST **.
+ | ^~"
+
+"get-data.sps:19.54-19.55: error: GET DATA: Syntax error expecting integer.
+ 19 | GET DATA /TYPE=TXT/FILE='x.txt' /IMPORTCASES=PERCENT **.
+ | ^~"
+
+"get-data.sps:20.34-20.48: warning: GET DATA: Ignoring obsolete IMPORTCASES subcommand. (N OF CASES or SAMPLE may be used to substitute.).
+ 20 | GET DATA /TYPE=TXT/FILE='x.txt' /IMPORTCASES=ALL.
+ | ^~~~~~~~~~~~~~~"
+
+"get-data.sps:20.49: error: GET DATA: Syntax error expecting `/'.
+ 20 | GET DATA /TYPE=TXT/FILE='x.txt' /IMPORTCASES=ALL.
+ | ^"
+
+get-data.sps:21: error: GET DATA: FIXED and DELIMITED arrangements are mutually exclusive.
+
+"get-data.sps:21.53-21.62: note: GET DATA: This syntax requires DELIMITED arrangement.
+ 21 | GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=FIXED /DELIMITERS=' '.
+ | ^~~~~~~~~~"
+
+"get-data.sps:21.34-21.50: note: GET DATA: This syntax requires FIXED arrangement.
+ 21 | GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=FIXED /DELIMITERS=' '.
+ | ^~~~~~~~~~~~~~~~~"
+
+get-data.sps:22: error: GET DATA: FIXED and DELIMITED arrangements are mutually exclusive.
+
+"get-data.sps:22.53-22.61: note: GET DATA: This syntax requires DELIMITED arrangement.
+ 22 | GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=FIXED /QUALIFIER='""'.
+ | ^~~~~~~~~"
+
+"get-data.sps:22.34-22.50: note: GET DATA: This syntax requires FIXED arrangement.
+ 22 | GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=FIXED /QUALIFIER='""'.
+ | ^~~~~~~~~~~~~~~~~"
+
+"get-data.sps:23.44-23.52: error: GET DATA: In compatible syntax mode, the QUALIFIER string must contain exactly one character.
+ 23 | GET DATA /TYPE=TXT/FILE='x.txt' /QUALIFIER='""' + ""'"".
+ | ^~~~~~~~~"
+
+"get-data.sps:24.65-24.66: error: GET DATA: Syntax error expecting integer.
+ 24 | GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=FIXED /VARIABLES / **.
+ | ^~"
+
+"get-data.sps:25.44-25.45: error: GET DATA: Syntax error expecting identifier.
+ 25 | GET DATA /TYPE=TXT/FILE='x.txt' /VARIABLES **.
+ | ^~"
+
+"get-data.sps:26.44-26.109: error: GET DATA: Identifier `a_very_long_name_that_exceeds_the_64_byte_limit_for_variable_names' exceeds 64-byte limit.
+ 26 | GET DATA /TYPE=TXT/FILE='x.txt' /VARIABLES a_very_long_name_that_exceeds_the_64_byte_limit_for_variable_names.
+ | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
+
+"get-data.sps:27.46-27.47: error: GET DATA: Syntax error expecting valid format specifier.
+ 27 | GET DATA /TYPE=TXT/FILE='x.txt' /VARIABLES x **.
+ | ^~"
+
+"get-data.sps:28.46-28.49: error: GET DATA: Input format F1.2 specifies 2 decimal places, but width 1 allows at most 1 decimals.
+ 28 | GET DATA /TYPE=TXT/FILE='x.txt' /VARIABLES x F1.2.
+ | ^~~~"
+
+"get-data.sps:29.65-29.66: error: GET DATA: Syntax error expecting integer.
+ 29 | GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=FIXED /VARIABLES x **.
+ | ^~"
+
+"get-data.sps:30.69-30.70: error: GET DATA: Syntax error expecting valid format specifier.
+ 30 | GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=FIXED /VARIABLES x 1-5 **.
+ | ^~"
+
+"get-data.sps:31.69-31.71: error: GET DATA: Unknown format type `FOO'.
+ 31 | GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=FIXED /VARIABLES x 1-5 FOO.
+ | ^~~"
+
+"get-data.sps:32.65-32.72: error: GET DATA: Input format DATE5 specifies width 5, but DATE requires a width between 8 and 40.
+ 32 | GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=FIXED /VARIABLES x 1-5 DATE.
+ | ^~~~~~~~"
+
+"get-data.sps:33.65-33.77: error: GET DATA: Output format DOLLAR1.2 specifies width 1, but DOLLAR requires a width between 2 and 40.
+ 33 | GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=FIXED /VARIABLES x 1-5 DOLLAR1.2.
+ | ^~~~~~~~~~~~~"
+
+"get-data.sps:34.71: error: GET DATA: x is a duplicate variable name.
+ 34 | GET DATA /TYPE=TXT/FILE='x.txt' /ARRANGEMENT=FIXED /VARIABLES x 1-5 F x 6-10 F.
+ | ^"
+
+"get-data.sps:36.21-36.22: error: GET DATA: Syntax error expecting `/CONNECT='.
+ 36 | GET DATA /TYPE=PSQL **.
+ | ^~"
+
+"get-data.sps:37.20-37.23: error: GET DATA: Syntax error expecting `/CONNECT='.
+ 37 | GET DATA /TYPE=PSQL/ **.
+ | ^~~~"
+
+"get-data.sps:38.20-38.30: error: GET DATA: Syntax error expecting `/CONNECT='.
+ 38 | GET DATA /TYPE=PSQL/CONNECT **.
+ | ^~~~~~~~~~~"
+
+"get-data.sps:39.50-39.51: error: GET DATA: Syntax error expecting integer between 1 and 32767 for ASSUMEDSTRWIDTH.
+ 39 | GET DATA /TYPE=PSQL/CONNECT='db'/ASSUMEDSTRWIDTH=**.
+ | ^~"
+
+"get-data.sps:40.40-40.41: error: GET DATA: Syntax error expecting positive integer for BSIZE.
+ 40 | GET DATA /TYPE=PSQL/CONNECT='db'/BSIZE=**.
+ | ^~"
+
+"get-data.sps:41.38-41.39: error: GET DATA: Syntax error expecting string.
+ 41 | GET DATA /TYPE=PSQL/CONNECT='db'/SQL=**.
+ | ^~"
+
+"get-data.sps:43.20-43.21: error: GET DATA: Syntax error expecting `/FILE='.
+ 43 | GET DATA /TYPE=GNM **.
+ | ^~"
+
+"get-data.sps:44.19-44.22: error: GET DATA: Syntax error expecting `/FILE='.
+ 44 | GET DATA /TYPE=GNM/ **.
+ | ^~~~"
+
+"get-data.sps:45.19-45.26: error: GET DATA: Syntax error expecting `/FILE='.
+ 45 | GET DATA /TYPE=GNM/FILE **.
+ | ^~~~~~~~"
+
+"get-data.sps:46.26-46.27: error: GET DATA: Syntax error expecting string.
+ 46 | GET DATA /TYPE=GNM/FILE= **.
+ | ^~"
+
+"get-data.sps:47.54-47.55: error: GET DATA: Syntax error expecting integer between 1 and 32767 for ASSUMEDSTRWIDTH.
+ 47 | GET DATA /TYPE=GNM/FILE='x.gnumeric'/ASSUMEDSTRWIDTH=**.
+ | ^~"
+
+"get-data.sps:48.49-48.50: error: GET DATA: Syntax error expecting string.
+ 48 | GET DATA /TYPE=GNM/FILE='x.gnumeric'/SHEET=NAME **.
+ | ^~"
+
+"get-data.sps:49.50-49.51: error: GET DATA: Syntax error expecting positive integer for INDEX.
+ 49 | GET DATA /TYPE=GNM/FILE='x.gnumeric'/SHEET=INDEX **.
+ | ^~"
+
+"get-data.sps:50.44-50.45: error: GET DATA: Syntax error expecting NAME or INDEX.
+ 50 | GET DATA /TYPE=GNM/FILE='x.gnumeric'/SHEET=**.
+ | ^~"
+
+"get-data.sps:51.54-51.55: error: GET DATA: Syntax error expecting string.
+ 51 | GET DATA /TYPE=GNM/FILE='x.gnumeric'/CELLRANGE=RANGE **.
+ | ^~"
+
+"get-data.sps:52.48-52.49: error: GET DATA: Syntax error expecting FULL or RANGE.
+ 52 | GET DATA /TYPE=GNM/FILE='x.gnumeric'/CELLRANGE=**.
+ | ^~"
+
+"get-data.sps:53.48-53.49: error: GET DATA: Syntax error expecting ON or OFF.
+ 53 | GET DATA /TYPE=GNM/FILE='x.gnumeric'/READNAMES=**.
+ | ^~"
+
+"get-data.sps:54.39-54.40: error: GET DATA: Syntax error expecting ASSUMEDSTRWIDTH, SHEET, CELLRANGE, or READNAMES.
+ 54 | GET DATA /TYPE=GNM/FILE='x.gnumeric'/ **.
+ | ^~"
+])
+AT_CLEANUP
\ No newline at end of file