From: Ben Pfaff Date: Sun, 21 Mar 2021 18:59:30 +0000 (-0700) Subject: SET: Reimplement parser without q2c. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=97466647616875cca6662b50b5eb467c8ef8c617;p=pspp SET: Reimplement parser without q2c. --- diff --git a/src/language/lexer/lexer.c b/src/language/lexer/lexer.c index 34b697efe2..b69bc9a5d0 100644 --- a/src/language/lexer/lexer.c +++ b/src/language/lexer/lexer.c @@ -269,23 +269,40 @@ lex_next_error (struct lexer *lexer, int n0, int n1, const char *format, ...) va_end (args); } -/* Prints a syntax error message saying that OPTION0 or one of the other - strings following it, up to the first NULL, is expected. */ +/* Prints a syntax error message saying that one of the strings provided as + varargs, up to the first NULL, is expected. */ void -(lex_error_expecting) (struct lexer *lexer, const char *option0, ...) +(lex_error_expecting) (struct lexer *lexer, ...) { - enum { MAX_OPTIONS = 8 }; - const char *options[MAX_OPTIONS + 1]; va_list args; - int n; - va_start (args, option0); - options[0] = option0; - n = 0; - while (n + 1 < MAX_OPTIONS && options[n] != NULL) - options[++n] = va_arg (args, const char *); + va_start (args, lexer); + lex_error_expecting_valist (lexer, args); va_end (args); +} + +/* Prints a syntax error message saying that one of the options provided in + ARGS, up to the first NULL, is expected. */ +void +lex_error_expecting_valist (struct lexer *lexer, va_list args) +{ + enum { MAX_OPTIONS = 9 }; + const char *options[MAX_OPTIONS]; + int n = 0; + while (n < MAX_OPTIONS) + { + const char *option = va_arg (args, const char *); + if (!option) + break; + options[n++] = option; + } + lex_error_expecting_array (lexer, options, n); +} + +void +lex_error_expecting_array (struct lexer *lexer, const char **options, size_t n) +{ switch (n) { case 0: @@ -334,7 +351,7 @@ void break; default: - NOT_REACHED (); + lex_error (lexer, NULL); } } diff --git a/src/language/lexer/lexer.h b/src/language/lexer/lexer.h index 91200ce6cd..e98dac00f5 100644 --- a/src/language/lexer/lexer.h +++ b/src/language/lexer/lexer.h @@ -161,9 +161,11 @@ void lex_next_error (struct lexer *, int n0, int n1, const char *, ...) PRINTF_FORMAT (4, 5); int lex_end_of_command (struct lexer *); -void lex_error_expecting (struct lexer *, const char *, ...) SENTINEL(0); +void lex_error_expecting (struct lexer *, ...) SENTINEL(0); #define lex_error_expecting(...) \ lex_error_expecting(__VA_ARGS__, NULL_SENTINEL) +void lex_error_expecting_valist (struct lexer *, va_list); +void lex_error_expecting_array (struct lexer *, const char **, size_t n); void lex_sbc_only_once (const char *); void lex_sbc_missing (const char *); diff --git a/src/language/utilities/automake.mk b/src/language/utilities/automake.mk index f9e6a4a668..7752792377 100644 --- a/src/language/utilities/automake.mk +++ b/src/language/utilities/automake.mk @@ -17,20 +17,14 @@ ## Process this file with automake to produce Makefile.in -*- makefile -*- -src_language_utilities_built_sources = \ - src/language/utilities/set.c - language_utilities_sources = \ src/language/utilities/cache.c \ src/language/utilities/cd.c \ src/language/utilities/date.c \ src/language/utilities/echo.c \ src/language/utilities/host.c \ + src/language/utilities/set.c \ src/language/utilities/title.c \ src/language/utilities/include.c \ src/language/utilities/output.c \ src/language/utilities/permissions.c - -all_q_sources += $(src_language_utilities_built_sources:.c=.q) -EXTRA_DIST += $(src_language_utilities_built_sources:.c=.q) -CLEANFILES += $(src_language_utilities_built_sources) diff --git a/src/language/utilities/set.c b/src/language/utilities/set.c new file mode 100644 index 0000000000..89a7052600 --- /dev/null +++ b/src/language/utilities/set.c @@ -0,0 +1,1323 @@ +/* PSPP - a program for statistical analysis. + Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012, 2013, 2014, 2015 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 + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "gl/vasnprintf.h" + +#include "data/casereader.h" +#include "data/data-in.h" +#include "data/data-out.h" +#include "data/dataset.h" +#include "data/dictionary.h" +#include "data/format.h" +#include "data/settings.h" +#include "data/value.h" +#include "data/variable.h" +#include "language/command.h" +#include "language/lexer/format-parser.h" +#include "language/lexer/lexer.h" +#include "libpspp/assertion.h" +#include "libpspp/compiler.h" +#include "libpspp/copyleft.h" +#include "libpspp/temp-file.h" +#include "libpspp/version.h" +#include "libpspp/float-format.h" +#include "libpspp/i18n.h" +#include "libpspp/integer-format.h" +#include "libpspp/message.h" +#include "math/random.h" +#include "output/driver.h" +#include "output/journal.h" +#include "output/pivot-table.h" + +#include "gl/xalloc.h" + +#include "gettext.h" +#define _(msgid) gettext (msgid) + +static bool +match_subcommand (struct lexer *lexer, const char *name) +{ + if (lex_match_id (lexer, name)) + { + lex_match (lexer, T_EQUALS); + return true; + } + else + return false; +} + +static int +parse_enum_valist (struct lexer *lexer, va_list args) +{ + for (;;) + { + const char *name = va_arg (args, char *); + if (!name) + return -1; + int value = va_arg (args, int); + + if (lex_match_id (lexer, name)) + return value; + } +} + +#define parse_enum(...) parse_enum (__VA_ARGS__, NULL_SENTINEL) +static int SENTINEL(0) +(parse_enum) (struct lexer *lexer, ...) +{ + va_list args; + + va_start (args, lexer); + int retval = parse_enum_valist (lexer, args); + va_end (args); + + return retval; +} + +#define force_parse_enum(...) force_parse_enum (__VA_ARGS__, NULL_SENTINEL) +static int SENTINEL(0) +(force_parse_enum) (struct lexer *lexer, ...) +{ + va_list args; + + va_start (args, lexer); + int retval = parse_enum_valist (lexer, args); + va_end (args); + + if (retval == -1) + { + enum { MAX_OPTIONS = 9 }; + const char *options[MAX_OPTIONS]; + int n = 0; + + va_start (args, lexer); + while (n < MAX_OPTIONS) + { + const char *name = va_arg (args, char *); + if (!name) + break; + va_arg (args, int); + + options[n++] = name; + } + va_end (args); + + lex_error_expecting_array (lexer, options, n); + } + + return retval; +} + +static int +parse_bool (struct lexer *lexer) +{ + return parse_enum (lexer, + "ON", true, "YES", true, + "OFF", false, "NO", false); +} + +static int +force_parse_bool (struct lexer *lexer) +{ + return force_parse_enum (lexer, + "ON", true, "YES", true, + "OFF", false, "NO", false); +} + +static bool +force_parse_int (struct lexer *lexer, int *integerp) +{ + if (!lex_force_int (lexer)) + return false; + *integerp = lex_integer (lexer); + lex_get (lexer); + return true; +} + +static bool +parse_output_routing (struct lexer *lexer, enum settings_output_type type) +{ + enum settings_output_devices devices; + if (lex_match_id (lexer, "ON") || lex_match_id (lexer, "BOTH")) + devices = SETTINGS_DEVICE_LISTING | SETTINGS_DEVICE_TERMINAL; + else if (lex_match_id (lexer, "TERMINAL")) + devices = SETTINGS_DEVICE_TERMINAL; + else if (lex_match_id (lexer, "LISTING")) + devices = SETTINGS_DEVICE_LISTING; + else if (lex_match_id (lexer, "OFF") || lex_match_id (lexer, "NONE")) + devices = 0; + else + { + lex_error (lexer, NULL); + return false; + } + + settings_set_output_routing (type, devices); + + return true; +} + +static bool +parse_integer_format (struct lexer *lexer, + void (*set_format) (enum integer_format)) +{ + int value = force_parse_enum (lexer, + "MSBFIRST", INTEGER_MSB_FIRST, + "LSBFIRST", INTEGER_LSB_FIRST, + "VAX", INTEGER_VAX, + "NATIVE", INTEGER_NATIVE); + if (value >= 0) + set_format (value); + return value >= 0; +} + +static bool +parse_real_format (struct lexer *lexer, + void (*set_format) (enum float_format)) +{ + int value = force_parse_enum (lexer, + "NATIVE", FLOAT_NATIVE_DOUBLE, + "ISL", FLOAT_IEEE_SINGLE_LE, + "ISB", FLOAT_IEEE_SINGLE_BE, + "IDL", FLOAT_IEEE_DOUBLE_LE, + "IDB", FLOAT_IEEE_DOUBLE_BE, + "VF", FLOAT_VAX_F, + "VD", FLOAT_VAX_D, + "VG", FLOAT_VAX_G, + "ZS", FLOAT_Z_SHORT, + "ZL", FLOAT_Z_LONG); + if (value >= 0) + set_format (value); + return value >= 0; +} + +static bool +parse_unimplemented (struct lexer *lexer, const char *name) +{ + msg (SW, _("%s is not yet implemented."), name); + if (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD) + lex_get (lexer); + return true; +} + +static bool +parse_ccx (struct lexer *lexer, enum fmt_type ccx) +{ + if (!lex_force_string (lexer)) + return false; + + settings_set_cc (lex_tokcstr (lexer), ccx); + lex_get (lexer); + return true; +} + +static bool +parse_BASETEXTDIRECTION (struct lexer *lexer) +{ + return parse_unimplemented (lexer, "BASETEXTDIRECTION"); +} + +static bool +parse_BLANKS (struct lexer *lexer) +{ + if (lex_match_id (lexer, "SYSMIS")) + settings_set_blanks (SYSMIS); + else + { + if (!lex_force_num (lexer)) + return false; + settings_set_blanks (lex_number (lexer)); + lex_get (lexer); + } + return true; +} + +static bool +parse_BLOCK (struct lexer *lexer) +{ + return parse_unimplemented (lexer, "BLOCK"); +} + +static bool +parse_BOX (struct lexer *lexer) +{ + return parse_unimplemented (lexer, "BOX"); +} + +static bool +parse_CACHE (struct lexer *lexer) +{ + return parse_unimplemented (lexer, "CACHE"); +} + +static bool +parse_CCA (struct lexer *lexer) +{ + return parse_ccx (lexer, FMT_CCA); +} + +static bool +parse_CCB (struct lexer *lexer) +{ + return parse_ccx (lexer, FMT_CCB); +} + +static bool +parse_CCC (struct lexer *lexer) +{ + return parse_ccx (lexer, FMT_CCC); +} + +static bool +parse_CCD (struct lexer *lexer) +{ + return parse_ccx (lexer, FMT_CCD); +} + +static bool +parse_CCE (struct lexer *lexer) +{ + return parse_ccx (lexer, FMT_CCE); +} + +static bool +parse_CELLSBREAK (struct lexer *lexer) +{ + return parse_unimplemented (lexer, "CELLSBREAK"); +} + +static bool +parse_CMPTRANS (struct lexer *lexer) +{ + return parse_unimplemented (lexer, "CMPTRANS"); +} + +static bool +parse_COMPRESSION (struct lexer *lexer) +{ + return parse_unimplemented (lexer, "COMPRESSION"); +} + +static bool +parse_CTEMPLATE (struct lexer *lexer) +{ + return parse_unimplemented (lexer, "CTEMPLATE"); +} + +static bool +parse_DECIMAL (struct lexer *lexer) +{ + int decimal_char = force_parse_enum (lexer, + "DOT", '.', + "COMMA", ','); + if (decimal_char != -1) + settings_set_decimal_char (decimal_char); + return decimal_char != -1; +} + +static bool +parse_EPOCH (struct lexer *lexer) +{ + if (lex_match_id (lexer, "AUTOMATIC")) + settings_set_epoch (-1); + else if (lex_is_integer (lexer)) + { + int new_epoch = lex_integer (lexer); + lex_get (lexer); + if (new_epoch < 1500) + { + msg (SE, _("%s must be 1500 or later."), "EPOCH"); + return false; + } + settings_set_epoch (new_epoch); + } + else + { + lex_error (lexer, _("expecting %s or year"), "AUTOMATIC"); + return false; + } + + return true; +} + +static bool +parse_ERRORS (struct lexer *lexer) +{ + return parse_output_routing (lexer, SETTINGS_OUTPUT_ERROR); +} + +static bool +parse_FORMAT (struct lexer *lexer) +{ + struct fmt_spec fmt; + + lex_match (lexer, T_EQUALS); + if (!parse_format_specifier (lexer, &fmt)) + return false; + + if (!fmt_check_output (&fmt)) + return false; + + if (fmt_is_string (fmt.type)) + { + char str[FMT_STRING_LEN_MAX + 1]; + msg (SE, _("%s requires numeric output format as an argument. " + "Specified format %s is of type string."), + "FORMAT", + fmt_to_string (&fmt, str)); + return false; + } + + settings_set_format (&fmt); + return true; +} + +static bool +parse_FUZZBITS (struct lexer *lexer) +{ + if (!lex_force_int (lexer)) + return false; + int fuzzbits = lex_integer (lexer); + lex_get (lexer); + + if (fuzzbits >= 0 && fuzzbits <= 20) + settings_set_fuzzbits (fuzzbits); + else + msg (SE, _("%s must be between 0 and 20."), "FUZZBITS"); + return true; +} + +static bool +parse_HEADER (struct lexer *lexer) +{ + return parse_unimplemented (lexer, "HEADER"); +} + +static bool +parse_INCLUDE (struct lexer *lexer) +{ + int include = force_parse_bool (lexer); + if (include != -1) + settings_set_include (include); + return include != -1; +} + +static bool +parse_JOURNAL (struct lexer *lexer) +{ + int b = parse_bool (lexer); + if (b == true) + journal_enable (); + else if (b == false) + journal_disable (); + else if (lex_is_string (lexer) || lex_token (lexer) == T_ID) + { + char *filename = utf8_to_filename (lex_tokcstr (lexer)); + journal_set_file_name (filename); + free (filename); + + lex_get (lexer); + } + else + { + lex_error (lexer, NULL); + return false; + } + return true; +} + +static bool +parse_LENGTH (struct lexer *lexer) +{ + int page_length; + + if (lex_match_id (lexer, "NONE")) + page_length = -1; + else + { + if (!lex_force_int (lexer)) + return false; + if (lex_integer (lexer) < 1) + { + msg (SE, _("%s must be at least %d."), "LENGTH", 1); + return false; + } + page_length = lex_integer (lexer); + lex_get (lexer); + } + + if (page_length != -1) + settings_set_viewlength (page_length); + + return true; +} + +static bool +parse_LOCALE (struct lexer *lexer) +{ + if (!lex_force_string (lexer)) + return false; + + /* Try the argument as an encoding name, then as a locale name or alias. */ + const char *s = lex_tokcstr (lexer); + if (valid_encoding (s)) + set_default_encoding (s); + else if (!set_encoding_from_locale (s)) + { + msg (ME, _("%s is not a recognized encoding or locale name"), s); + return false; + } + + lex_get (lexer); + return true; +} + +static bool +parse_MESSAGES (struct lexer *lexer) +{ + return parse_output_routing (lexer, SETTINGS_OUTPUT_NOTE); +} + +static bool +parse_MEXPAND (struct lexer *lexer) +{ + return parse_unimplemented (lexer, "MEXPAND"); +} + +static bool +parse_MITERATE (struct lexer *lexer) +{ + return parse_unimplemented (lexer, "MITERATE"); +} + +static bool +parse_MNEST (struct lexer *lexer) +{ + return parse_unimplemented (lexer, "MNEST"); +} + +static bool +parse_MPRINT (struct lexer *lexer) +{ + return parse_unimplemented (lexer, "MPRINT"); +} + +static bool +parse_MXERRS (struct lexer *lexer) +{ + int n; + if (!force_parse_int (lexer, &n)) + return false; + + if (n >= 1) + settings_set_max_messages (MSG_S_ERROR, n); + else + msg (SE, _("%s must be at least 1."), "MXERRS"); + return true; +} + +static bool +parse_MXLOOPS (struct lexer *lexer) +{ + int n; + if (!force_parse_int (lexer, &n)) + return false; + + if (n >= 1) + settings_set_mxloops (n); + else + msg (SE, _("%s must be at least 1."), "MXLOOPS"); + return true; +} + +static bool +parse_MXWARNS (struct lexer *lexer) +{ + int n; + if (!force_parse_int (lexer, &n)) + return false; + + if (n >= 0) + settings_set_max_messages (MSG_S_WARNING, n); + else + msg (SE, _("%s must not be negative."), "MXWARNS"); + return true; +} + +static bool +parse_PRINTBACK (struct lexer *lexer) +{ + return parse_output_routing (lexer, SETTINGS_OUTPUT_SYNTAX); +} + +static bool +parse_RESULTS (struct lexer *lexer) +{ + return parse_output_routing (lexer, SETTINGS_OUTPUT_RESULT); +} + +static bool +parse_RIB (struct lexer *lexer) +{ + return parse_integer_format (lexer, settings_set_input_integer_format); +} + +static bool +parse_RRB (struct lexer *lexer) +{ + return parse_real_format (lexer, settings_set_input_float_format); +} + +static bool +parse_SAFER (struct lexer *lexer) +{ + bool ok = force_parse_enum (lexer, "ON", true, "YES", true) != -1; + if (ok) + settings_set_safer_mode (); + return ok; +} + +static bool +parse_SCOMPRESSION (struct lexer *lexer) +{ + int value = force_parse_bool (lexer); + if (value >= 0) + settings_set_scompression (value); + return value >= 0; +} + +static bool +parse_SEED (struct lexer *lexer) +{ + if (lex_match_id (lexer, "RANDOM")) + set_rng (time (0)); + else + { + if (!lex_force_num (lexer)) + return false; + set_rng (lex_number (lexer)); + lex_get (lexer); + } + + return true; +} + +static bool +parse_SMALL (struct lexer *lexer) +{ + if (!lex_force_num (lexer)) + return false; + settings_set_small (lex_number (lexer)); + lex_get (lexer); + return true; +} + +static bool +parse_TNUMBERS (struct lexer *lexer) +{ + int value = force_parse_enum (lexer, + "LABELS", SETTINGS_VALUE_SHOW_LABEL, + "VALUES", SETTINGS_VALUE_SHOW_VALUE, + "BOTH", SETTINGS_VALUE_SHOW_BOTH); + if (value >= 0) + settings_set_show_values (value); + return value >= 0; +} + +static bool +parse_TVARS (struct lexer *lexer) +{ + int value = force_parse_enum (lexer, + "LABELS", SETTINGS_VALUE_SHOW_LABEL, + "NAMES", SETTINGS_VALUE_SHOW_VALUE, + "BOTH", SETTINGS_VALUE_SHOW_BOTH); + if (value >= 0) + settings_set_show_variables (value); + return value >= 0; +} + +static bool +parse_TLOOK (struct lexer *lexer) +{ + if (lex_match_id (lexer, "NONE")) + pivot_table_look_set_default (pivot_table_look_builtin_default ()); + else if (lex_is_string (lexer)) + { + struct pivot_table_look *look; + char *error = pivot_table_look_read (lex_tokcstr (lexer), &look); + lex_get (lexer); + + if (error) + { + msg (SE, "%s", error); + free (error); + return false; + } + + pivot_table_look_set_default (look); + pivot_table_look_unref (look); + } + + return true; +} + +static bool +parse_UNDEFINED (struct lexer *lexer) +{ + int value = force_parse_enum (lexer, + "WARN", true, + "NOWARN", false); + if (value >= 0) + settings_set_undefined (value); + return value >= 0; +} + +static bool +parse_WIB (struct lexer *lexer) +{ + return parse_integer_format (lexer, settings_set_output_integer_format); +} + +static bool +parse_WRB (struct lexer *lexer) +{ + return parse_real_format (lexer, settings_set_output_float_format); +} + +static bool +parse_WIDTH (struct lexer *lexer) +{ + if (lex_match_id (lexer, "NARROW")) + settings_set_viewwidth (79); + else if (lex_match_id (lexer, "WIDE")) + settings_set_viewwidth (131); + else + { + if (!lex_force_int (lexer)) + return 0; + if (lex_integer (lexer) < 40) + { + msg (SE, _("%s must be at least %d."), "WIDTH", 40); + return 0; + } + settings_set_viewwidth (lex_integer (lexer)); + lex_get (lexer); + } + + return 1; +} + +static bool +parse_WORKSPACE (struct lexer *lexer) +{ + if (!lex_force_int (lexer)) + return false; + int workspace = lex_integer (lexer); + lex_get (lexer); + + if (workspace < 1024 && !settings_get_testing_mode ()) + msg (SE, _("%s must be at least 1MB"), "WORKSPACE"); + else if (workspace <= 0) + msg (SE, _("%s must be positive"), "WORKSPACE"); + else + settings_set_workspace (workspace * 1024L); + return true; +} + +static bool +parse_setting (struct lexer *lexer) +{ + struct setting + { + const char *name; + bool (*function) (struct lexer *); + }; + const struct setting settings[] = { + { "BASETEXTDIRECTION", parse_BASETEXTDIRECTION }, + { "BLANKS", parse_BLANKS }, + { "BLOCK", parse_BLOCK }, + { "BOX", parse_BOX }, + { "CACHE", parse_CACHE }, + { "CCA", parse_CCA }, + { "CCB", parse_CCB }, + { "CCC", parse_CCC }, + { "CCD", parse_CCD }, + { "CCE", parse_CCE }, + { "CELLSBREAK", parse_CELLSBREAK }, + { "CMPTRANS", parse_CMPTRANS }, + { "COMPRESSION", parse_COMPRESSION }, + { "CTEMPLATE", parse_CTEMPLATE }, + { "DECIMAL", parse_DECIMAL }, + { "EPOCH", parse_EPOCH }, + { "ERRORS", parse_ERRORS }, + { "FORMAT", parse_FORMAT }, + { "FUZZBITS", parse_FUZZBITS }, + { "HEADER", parse_HEADER }, + { "INCLUDE", parse_INCLUDE }, + { "JOURNAL", parse_JOURNAL }, + { "LENGTH", parse_LENGTH }, + { "LOCALE", parse_LOCALE }, + { "MESSAGES", parse_MESSAGES }, + { "MEXPAND", parse_MEXPAND }, + { "MITERATE", parse_MITERATE }, + { "MNEST", parse_MNEST }, + { "MPRINT", parse_MPRINT }, + { "MXERRS", parse_MXERRS }, + { "MXLOOPS", parse_MXLOOPS }, + { "MXWARNS", parse_MXWARNS }, + { "PRINTBACK", parse_PRINTBACK }, + { "RESULTS", parse_RESULTS }, + { "RIB", parse_RIB }, + { "RRB", parse_RRB }, + { "SAFER", parse_SAFER }, + { "SCOMPRESSION", parse_SCOMPRESSION }, + { "SEED", parse_SEED }, + { "SMALL", parse_SMALL }, + { "TNUMBERS", parse_TNUMBERS }, + { "TVARS", parse_TVARS }, + { "TLOOK", parse_TLOOK }, + { "UNDEFINED", parse_UNDEFINED }, + { "WIB", parse_WIB }, + { "WRB", parse_WRB }, + { "WIDTH", parse_WIDTH }, + { "WORKSPACE", parse_WORKSPACE }, + }; + enum { N_SETTINGS = sizeof settings / sizeof *settings }; + + for (size_t i = 0; i < N_SETTINGS; i++) + if (match_subcommand (lexer, settings[i].name)) + return settings[i].function (lexer); + + lex_error (lexer, NULL); + return false; +} + +int +cmd_set (struct lexer *lexer, struct dataset *ds UNUSED) +{ + for (;;) + { + lex_match (lexer, T_SLASH); + if (lex_token (lexer) == T_ENDCMD) + break; + + if (!parse_setting (lexer)) + return CMD_FAILURE; + } + + return CMD_SUCCESS; +} + +static char * +show_output_routing (enum settings_output_type type) +{ + enum settings_output_devices devices; + const char *s; + + devices = settings_get_output_routing (type); + if (devices & SETTINGS_DEVICE_LISTING) + s = devices & SETTINGS_DEVICE_TERMINAL ? "BOTH" : "LISTING"; + else if (devices & SETTINGS_DEVICE_TERMINAL) + s = "TERMINAL"; + else + s = "NONE"; + + return xstrdup (s); +} + +static char * +show_blanks (const struct dataset *ds UNUSED) +{ + return (settings_get_blanks () == SYSMIS + ? xstrdup ("SYSMIS") + : xasprintf ("%.*g", DBL_DIG + 1, settings_get_blanks ())); +} + +static char * +show_cc (enum fmt_type type) +{ + return fmt_number_style_to_string (fmt_settings_get_style ( + settings_get_fmt_settings (), type)); +} + +static char * +show_cca (const struct dataset *ds UNUSED) +{ + return show_cc (FMT_CCA); +} + +static char * +show_ccb (const struct dataset *ds UNUSED) +{ + return show_cc (FMT_CCB); +} + +static char * +show_ccc (const struct dataset *ds UNUSED) +{ + return show_cc (FMT_CCC); +} + +static char * +show_ccd (const struct dataset *ds UNUSED) +{ + return show_cc (FMT_CCD); +} + +static char * +show_cce (const struct dataset *ds UNUSED) +{ + return show_cc (FMT_CCE); +} + +static char * +show_decimals (const struct dataset *ds UNUSED) +{ + return xasprintf ("`%c'", settings_get_fmt_settings ()->decimal); +} + +static char * +show_errors (const struct dataset *ds UNUSED) +{ + return show_output_routing (SETTINGS_OUTPUT_ERROR); +} + +static char * +show_format (const struct dataset *ds UNUSED) +{ + char str[FMT_STRING_LEN_MAX + 1]; + return xstrdup (fmt_to_string (settings_get_format (), str)); +} + +static char * +show_fuzzbits (const struct dataset *ds UNUSED) +{ + return xasprintf ("%d", settings_get_fuzzbits ()); +} + +static char * +show_journal (const struct dataset *ds UNUSED) +{ + return (journal_is_enabled () + ? xasprintf ("\"%s\"", journal_get_file_name ()) + : xstrdup ("disabled")); +} + +static char * +show_length (const struct dataset *ds UNUSED) +{ + return xasprintf ("%d", settings_get_viewlength ()); +} + +static char * +show_locale (const struct dataset *ds UNUSED) +{ + return xstrdup (get_default_encoding ()); +} + +static char * +show_messages (const struct dataset *ds UNUSED) +{ + return show_output_routing (SETTINGS_OUTPUT_NOTE); +} + +static char * +show_printback (const struct dataset *ds UNUSED) +{ + return show_output_routing (SETTINGS_OUTPUT_SYNTAX); +} + +static char * +show_results (const struct dataset *ds UNUSED) +{ + return show_output_routing (SETTINGS_OUTPUT_RESULT); +} + +static char * +show_mxerrs (const struct dataset *ds UNUSED) +{ + return xasprintf ("%d", settings_get_max_messages (MSG_S_ERROR)); +} + +static char * +show_mxloops (const struct dataset *ds UNUSED) +{ + return xasprintf ("%d", settings_get_mxloops ()); +} + +static char * +show_mxwarns (const struct dataset *ds UNUSED) +{ + return xasprintf ("%d", settings_get_max_messages (MSG_S_WARNING)); +} + +/* Returns a name for the given INTEGER_FORMAT value. */ +static char * +show_integer_format (enum integer_format integer_format) +{ + return xasprintf ("%s (%s)", + (integer_format == INTEGER_MSB_FIRST ? "MSBFIRST" + : integer_format == INTEGER_LSB_FIRST ? "LSBFIRST" + : "VAX"), + integer_format == INTEGER_NATIVE ? "NATIVE" : "nonnative"); +} + +/* Returns a name for the given FLOAT_FORMAT value. */ +static char * +show_float_format (enum float_format float_format) +{ + const char *format_name = ""; + + switch (float_format) + { + case FLOAT_IEEE_SINGLE_LE: + format_name = _("ISL (32-bit IEEE 754 single, little-endian)"); + break; + case FLOAT_IEEE_SINGLE_BE: + format_name = _("ISB (32-bit IEEE 754 single, big-endian)"); + break; + case FLOAT_IEEE_DOUBLE_LE: + format_name = _("IDL (64-bit IEEE 754 double, little-endian)"); + break; + case FLOAT_IEEE_DOUBLE_BE: + format_name = _("IDB (64-bit IEEE 754 double, big-endian)"); + break; + + case FLOAT_VAX_F: + format_name = _("VF (32-bit VAX F, VAX-endian)"); + break; + case FLOAT_VAX_D: + format_name = _("VD (64-bit VAX D, VAX-endian)"); + break; + case FLOAT_VAX_G: + format_name = _("VG (64-bit VAX G, VAX-endian)"); + break; + + case FLOAT_Z_SHORT: + format_name = _("ZS (32-bit IBM Z hexadecimal short, big-endian)"); + break; + case FLOAT_Z_LONG: + format_name = _("ZL (64-bit IBM Z hexadecimal long, big-endian)"); + break; + + case FLOAT_FP: + case FLOAT_HEX: + NOT_REACHED (); + } + + return xasprintf ("%s (%s)", format_name, + (float_format == FLOAT_NATIVE_DOUBLE + ? "NATIVE" : "nonnative")); +} + +static char * +show_rib (const struct dataset *ds UNUSED) +{ + return show_integer_format (settings_get_input_integer_format ()); +} + +static char * +show_rrb (const struct dataset *ds UNUSED) +{ + return show_float_format (settings_get_input_float_format ()); +} + +static char * +show_scompression (const struct dataset *ds UNUSED) +{ + return xstrdup (settings_get_scompression () ? "ON" : "OFF"); +} + +static char * +show_undefined (const struct dataset *ds UNUSED) +{ + return xstrdup (settings_get_undefined () ? "WARN" : "NOWARN"); +} + +static char * +show_weight (const struct dataset *ds) +{ + const struct variable *var = dict_get_weight (dataset_dict (ds)); + return xstrdup (var != NULL ? var_get_name (var) : "OFF"); +} + +static char * +show_wib (const struct dataset *ds UNUSED) +{ + return show_integer_format (settings_get_output_integer_format ()); +} + +static char * +show_wrb (const struct dataset *ds UNUSED) +{ + return show_float_format (settings_get_output_float_format ()); +} + +static char * +show_width (const struct dataset *ds UNUSED) +{ + return xasprintf ("%d", settings_get_viewwidth ()); +} + +static char * +show_workspace (const struct dataset *ds UNUSED) +{ + size_t ws = settings_get_workspace () / 1024L; + return xasprintf ("%zu", ws); +} + +static char * +show_current_directory (const struct dataset *ds UNUSED) +{ + char *buf = NULL; + char *wd = NULL; + size_t len = 256; + + do + { + len <<= 1; + buf = xrealloc (buf, len); + } + while (NULL == (wd = getcwd (buf, len))); + + return wd; +} + +static char * +show_tempdir (const struct dataset *ds UNUSED) +{ + return strdup (temp_dir_name ()); +} + +static char * +show_version (const struct dataset *ds UNUSED) +{ + return strdup (announced_version); +} + +static char * +show_system (const struct dataset *ds UNUSED) +{ + return strdup (host_system); +} + +static char * +show_n (const struct dataset *ds) +{ + casenumber n; + size_t l; + + const struct casereader *reader = dataset_source (ds); + + if (reader == NULL) + return strdup (_("Unknown")); + + n = casereader_count_cases (reader); + + return asnprintf (NULL, &l, "%ld", n); +} + + +struct show_sbc + { + const char *name; + char *(*function) (const struct dataset *); + }; + +const struct show_sbc show_table[] = + { + {"BLANKS", show_blanks}, + {"CCA", show_cca}, + {"CCB", show_ccb}, + {"CCC", show_ccc}, + {"CCD", show_ccd}, + {"CCE", show_cce}, + {"DECIMALS", show_decimals}, + {"DIRECTORY", show_current_directory}, + {"ENVIRONMENT", show_system}, + {"ERRORS", show_errors}, + {"FORMAT", show_format}, + {"FUZZBITS", show_fuzzbits}, + {"JOURNAL", show_journal}, + {"LENGTH", show_length}, + {"LOCALE", show_locale}, + {"MESSAGES", show_messages}, + {"MXERRS", show_mxerrs}, + {"MXLOOPS", show_mxloops}, + {"MXWARNS", show_mxwarns}, + {"N", show_n}, + {"PRINTBACk", show_printback}, + {"RESULTS", show_results}, + {"RIB", show_rib}, + {"RRB", show_rrb}, + {"SCOMPRESSION", show_scompression}, + {"TEMPDIR", show_tempdir}, + {"UNDEFINED", show_undefined}, + {"VERSION", show_version}, + {"WEIGHT", show_weight}, + {"WIB", show_wib}, + {"WRB", show_wrb}, + {"WIDTH", show_width}, + {"WORKSPACE", show_workspace}, + }; + +static void +do_show (const struct dataset *ds, const struct show_sbc *sbc) +{ + char *value = sbc->function (ds); + msg (SN, _("%s is %s."), sbc->name, value); + free (value); +} + +static void +show_all (const struct dataset *ds) +{ + size_t i; + + for (i = 0; i < sizeof show_table / sizeof *show_table; i++) + do_show (ds, &show_table[i]); +} + +static void +show_all_cc (const struct dataset *ds) +{ + int i; + + for (i = 0; i < sizeof show_table / sizeof *show_table; i++) + { + const struct show_sbc *sbc = &show_table[i]; + if (!strncmp (sbc->name, "CC", 2)) + do_show (ds, sbc); + } +} + +static void +show_warranty (const struct dataset *ds UNUSED) +{ + fputs (lack_of_warranty, stdout); +} + +static void +show_copying (const struct dataset *ds UNUSED) +{ + fputs (copyleft, stdout); +} + + +int +cmd_show (struct lexer *lexer, struct dataset *ds) +{ + if (lex_token (lexer) == T_ENDCMD) + { + show_all (ds); + return CMD_SUCCESS; + } + + do + { + if (lex_match (lexer, T_ALL)) + show_all (ds); + else if (lex_match_id (lexer, "CC")) + show_all_cc (ds); + else if (lex_match_id (lexer, "WARRANTY")) + show_warranty (ds); + else if (lex_match_id (lexer, "COPYING") || lex_match_id (lexer, "LICENSE")) + show_copying (ds); + else if (lex_token (lexer) == T_ID) + { + int i; + + for (i = 0; i < sizeof show_table / sizeof *show_table; i++) + { + const struct show_sbc *sbc = &show_table[i]; + if (lex_match_id (lexer, sbc->name)) + { + do_show (ds, sbc); + goto found; + } + } + lex_error (lexer, NULL); + return CMD_FAILURE; + + found: ; + } + else + { + lex_error (lexer, NULL); + return CMD_FAILURE; + } + + lex_match (lexer, T_SLASH); + } + while (lex_token (lexer) != T_ENDCMD); + + return CMD_SUCCESS; +} + +#define MAX_SAVED_SETTINGS 5 + +static struct settings *saved_settings[MAX_SAVED_SETTINGS]; +static int n_saved_settings; + +int +cmd_preserve (struct lexer *lexer UNUSED, struct dataset *ds UNUSED) +{ + if (n_saved_settings < MAX_SAVED_SETTINGS) + { + saved_settings[n_saved_settings++] = settings_get (); + return CMD_SUCCESS; + } + else + { + msg (SE, _("Too many %s commands without a %s: at most " + "%d levels of saved settings are allowed."), + "PRESERVE", "RESTORE", + MAX_SAVED_SETTINGS); + return CMD_CASCADING_FAILURE; + } +} + +int +cmd_restore (struct lexer *lexer UNUSED, struct dataset *ds UNUSED) +{ + if (n_saved_settings > 0) + { + struct settings *s = saved_settings[--n_saved_settings]; + settings_set (s); + settings_destroy (s); + return CMD_SUCCESS; + } + else + { + msg (SE, _("%s without matching %s."), "RESTORE", "PRESERVE"); + return CMD_FAILURE; + } +} + +/* + Local Variables: + mode: c + End: +*/ diff --git a/src/language/utilities/set.q b/src/language/utilities/set.q deleted file mode 100644 index aa7f8b8034..0000000000 --- a/src/language/utilities/set.q +++ /dev/null @@ -1,1126 +0,0 @@ -/* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012, 2013, 2014, 2015 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 - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -#include - -#include -#include -#include -#include -#include -#include - -#include "gl/vasnprintf.h" - -#include "data/casereader.h" -#include "data/data-in.h" -#include "data/data-out.h" -#include "data/dataset.h" -#include "data/dictionary.h" -#include "data/format.h" -#include "data/settings.h" -#include "data/value.h" -#include "data/variable.h" -#include "language/command.h" -#include "language/lexer/format-parser.h" -#include "language/lexer/lexer.h" -#include "libpspp/compiler.h" -#include "libpspp/copyleft.h" -#include "libpspp/temp-file.h" -#include "libpspp/version.h" -#include "libpspp/float-format.h" -#include "libpspp/i18n.h" -#include "libpspp/integer-format.h" -#include "libpspp/message.h" -#include "math/random.h" -#include "output/driver.h" -#include "output/journal.h" -#include "output/pivot-table.h" - -#if HAVE_LIBTERMCAP -#if HAVE_TERMCAP_H -#include -#else /* !HAVE_TERMCAP_H */ -int tgetent (char *, const char *); -int tgetnum (const char *); -#endif /* !HAVE_TERMCAP_H */ -#endif /* !HAVE_LIBTERMCAP */ - -#include "xalloc.h" - -#include "gettext.h" -#define _(msgid) gettext (msgid) - -/* (specification) - "SET" (stc_): - blanks=custom; - block=string; - boxstring=string; - case=size:upper/uplow; - cca=string; - ccb=string; - ccc=string; - ccd=string; - cce=string; - compression=compress:on/off; - cpi=integer; - decimal=dec:dot/comma; - epoch=custom; - errors=custom; - format=custom; - fuzzbits=integer; - headers=headers:no/yes/blank; - highres=hires:on/off; - histogram=string; - include=inc:on/off; - journal=custom; - log=custom; - length=custom; - locale=custom; - lowres=lores:auto/on/off; - lpi=integer; - menus=menus:standard/extended; - messages=custom; - mexpand=mexp:on/off; - miterate=integer; - mnest=integer; - mprint=mprint:on/off; - mxerrs=integer; - mxloops=integer; - mxmemory=integer; - mxwarns=integer; - printback=custom; - results=custom; - rib=rib:msbfirst/lsbfirst/vax/native; - rrb=rrb:native/isl/isb/idl/idb/vf/vd/vg/zs/zl; - safer=safe:on; - scompression=scompress:on/off; - scripttab=string; - seed=custom; - small=double; - tnumbers=custom; - tvars=custom; - tb1=string; - tbfonts=string; - tlook=custom; - undefined=undef:warn/nowarn; - wib=wib:msbfirst/lsbfirst/vax/native; - wrb=wrb:native/isl/isb/idl/idb/vf/vd/vg/zs/zl; - width=custom; - workspace=integer; - xsort=xsort:yes/no. -*/ - -/* (headers) */ - -/* (declarations) */ - -/* (functions) */ - -static enum integer_format stc_to_integer_format (int stc); -static enum float_format stc_to_float_format (int stc); - -int -cmd_set (struct lexer *lexer, struct dataset *ds) -{ - struct cmd_set cmd; - - if (!parse_set (lexer, ds, &cmd, NULL)) - { - return CMD_FAILURE; - } - - if (cmd.sbc_cca) - settings_set_cc ( cmd.s_cca, FMT_CCA); - if (cmd.sbc_ccb) - settings_set_cc ( cmd.s_ccb, FMT_CCB); - if (cmd.sbc_ccc) - settings_set_cc ( cmd.s_ccc, FMT_CCC); - if (cmd.sbc_ccd) - settings_set_cc ( cmd.s_ccd, FMT_CCD); - if (cmd.sbc_cce) - settings_set_cc ( cmd.s_cce, FMT_CCE); - - if (cmd.sbc_decimal) - settings_set_decimal_char (cmd.dec == STC_DOT ? '.' : ','); - if (cmd.sbc_fuzzbits) - { - int fuzzbits = cmd.n_fuzzbits[0]; - if (fuzzbits >= 0 && fuzzbits <= 20) - settings_set_fuzzbits (fuzzbits); - else - msg (SE, _("%s must be between 0 and 20."), "FUZZBITS"); - } - - if (cmd.sbc_include) - settings_set_include (cmd.inc == STC_ON); - if (cmd.sbc_mxerrs) - { - if (cmd.n_mxerrs[0] >= 1) - settings_set_max_messages (MSG_S_ERROR, cmd.n_mxerrs[0]); - else - msg (SE, _("%s must be at least 1."), "MXERRS"); - } - if (cmd.sbc_mxloops) - { - if (cmd.n_mxloops[0] >= 1) - settings_set_mxloops (cmd.n_mxloops[0]); - else - msg (SE, _("%s must be at least 1."), "MXLOOPS"); - } - if (cmd.sbc_mxwarns) - { - if (cmd.n_mxwarns[0] >= 0) - settings_set_max_messages (MSG_S_WARNING, cmd.n_mxwarns[0]); - else - msg (SE, _("%s must not be negative."), "MXWARNS"); - } - if (cmd.sbc_rib) - settings_set_input_integer_format (stc_to_integer_format (cmd.rib)); - if (cmd.sbc_rrb) - settings_set_input_float_format (stc_to_float_format (cmd.rrb)); - if (cmd.sbc_safer) - settings_set_safer_mode (); - if (cmd.sbc_scompression) - settings_set_scompression (cmd.scompress == STC_ON); - if (cmd.sbc_small) - settings_set_small (cmd.n_small[0]); - if (cmd.sbc_undefined) - settings_set_undefined (cmd.undef == STC_WARN); - if (cmd.sbc_wib) - settings_set_output_integer_format (stc_to_integer_format (cmd.wib)); - if (cmd.sbc_wrb) - settings_set_output_float_format (stc_to_float_format (cmd.wrb)); - if (cmd.sbc_workspace) - { - if ( cmd.n_workspace[0] < 1024 && ! settings_get_testing_mode ()) - msg (SE, _("%s must be at least 1MB"), "WORKSPACE"); - else if (cmd.n_workspace[0] <= 0) - msg (SE, _("%s must be positive"), "WORKSPACE"); - else - settings_set_workspace (cmd.n_workspace[0] * 1024L); - } - - if (cmd.sbc_block) - msg (SW, _("%s is obsolete."), "BLOCK"); - if (cmd.sbc_boxstring) - msg (SW, _("%s is obsolete."), "BOXSTRING"); - if (cmd.sbc_cpi) - msg (SW, _("%s is obsolete."), "CPI"); - if (cmd.sbc_histogram) - msg (SW, _("%s is obsolete."), "HISTOGRAM"); - if (cmd.sbc_lpi) - msg (SW, _("%s is obsolete."), "LPI"); - if (cmd.sbc_menus) - msg (SW, _("%s is obsolete."), "MENUS"); - if (cmd.sbc_xsort) - msg (SW, _("%s is obsolete."), "XSORT"); - if (cmd.sbc_mxmemory) - msg (SE, _("%s is obsolete."), "MXMEMORY"); - if (cmd.sbc_scripttab) - msg (SE, _("%s is obsolete."), "SCRIPTTAB"); - if (cmd.sbc_tbfonts) - msg (SW, _("%s is obsolete."), "TBFONTS"); - if (cmd.sbc_tb1 && cmd.s_tb1) - msg (SW, _("%s is obsolete."), "TB1"); - - if (cmd.sbc_case) - msg (SW, _("%s is not yet implemented."), "CASE"); - - if (cmd.sbc_compression) - msg (SW, _("Active file compression is not implemented.")); - - free_set (&cmd); - - return CMD_SUCCESS; -} - -/* Returns the integer_format value corresponding to STC, - which should be the value of cmd.rib or cmd.wib. */ -static enum integer_format -stc_to_integer_format (int stc) -{ - return (stc == STC_MSBFIRST ? INTEGER_MSB_FIRST - : stc == STC_LSBFIRST ? INTEGER_LSB_FIRST - : stc == STC_VAX ? INTEGER_VAX - : INTEGER_NATIVE); -} - -/* Returns the float_format value corresponding to STC, - which should be the value of cmd.rrb or cmd.wrb. */ -static enum float_format -stc_to_float_format (int stc) -{ - switch (stc) - { - case STC_NATIVE: - return FLOAT_NATIVE_DOUBLE; - - case STC_ISL: - return FLOAT_IEEE_SINGLE_LE; - case STC_ISB: - return FLOAT_IEEE_SINGLE_BE; - case STC_IDL: - return FLOAT_IEEE_DOUBLE_LE; - case STC_IDB: - return FLOAT_IEEE_DOUBLE_BE; - - case STC_VF: - return FLOAT_VAX_F; - case STC_VD: - return FLOAT_VAX_D; - case STC_VG: - return FLOAT_VAX_G; - - case STC_ZS: - return FLOAT_Z_SHORT; - case STC_ZL: - return FLOAT_Z_LONG; - } - - NOT_REACHED (); -} - -static int -set_output_routing (struct lexer *lexer, enum settings_output_type type) -{ - enum settings_output_devices devices; - - lex_match (lexer, T_EQUALS); - if (lex_match_id (lexer, "ON") || lex_match_id (lexer, "BOTH")) - devices = SETTINGS_DEVICE_LISTING | SETTINGS_DEVICE_TERMINAL; - else if (lex_match_id (lexer, "TERMINAL")) - devices = SETTINGS_DEVICE_TERMINAL; - else if (lex_match_id (lexer, "LISTING")) - devices = SETTINGS_DEVICE_LISTING; - else if (lex_match_id (lexer, "OFF") || lex_match_id (lexer, "NONE")) - devices = 0; - else - { - lex_error (lexer, NULL); - return 0; - } - - settings_set_output_routing (type, devices); - - return 1; -} - -/* Parses the BLANKS subcommand, which controls the value that - completely blank fields in numeric data imply. X, Wnd: Syntax is - SYSMIS or a numeric value. */ -static int -stc_custom_blanks (struct lexer *lexer, - struct dataset *ds UNUSED, - struct cmd_set *cmd UNUSED, void *aux UNUSED) -{ - lex_match (lexer, T_EQUALS); - if (lex_match_id (lexer, "SYSMIS")) - { - lex_get (lexer); - settings_set_blanks (SYSMIS); - } - else - { - if (!lex_force_num (lexer)) - return 0; - settings_set_blanks (lex_number (lexer)); - lex_get (lexer); - } - return 1; -} - -static int -stc_custom_tnumbers (struct lexer *lexer, - struct dataset *ds UNUSED, - struct cmd_set *cmd UNUSED, void *aux UNUSED) -{ - lex_match (lexer, T_EQUALS); - - if (lex_match_id (lexer, "VALUES")) - settings_set_show_values (SETTINGS_VALUE_SHOW_VALUE); - else if (lex_match_id (lexer, "LABELS")) - settings_set_show_values (SETTINGS_VALUE_SHOW_LABEL); - else if (lex_match_id (lexer, "BOTH")) - settings_set_show_values (SETTINGS_VALUE_SHOW_BOTH); - else - { - lex_error_expecting (lexer, "VALUES", "LABELS", "BOTH"); - return 0; - } - - return 1; -} - - -static int -stc_custom_tvars (struct lexer *lexer, - struct dataset *ds UNUSED, - struct cmd_set *cmd UNUSED, void *aux UNUSED) -{ - lex_match (lexer, T_EQUALS); - - if (lex_match_id (lexer, "NAMES")) - settings_set_show_variables (SETTINGS_VALUE_SHOW_VALUE); - else if (lex_match_id (lexer, "LABELS")) - settings_set_show_variables (SETTINGS_VALUE_SHOW_LABEL); - else if (lex_match_id (lexer, "BOTH")) - settings_set_show_variables (SETTINGS_VALUE_SHOW_BOTH); - else - { - lex_error_expecting (lexer, "NAMES", "LABELS", "BOTH"); - return 0; - } - - return 1; -} - -static int -stc_custom_tlook (struct lexer *lexer, - struct dataset *ds UNUSED, - struct cmd_set *cmd UNUSED, void *aux UNUSED) -{ - lex_match (lexer, T_EQUALS); - - if (lex_match_id (lexer, "NONE")) - pivot_table_look_set_default (pivot_table_look_builtin_default ()); - else if (lex_is_string (lexer)) - { - struct pivot_table_look *look; - char *error = pivot_table_look_read (lex_tokcstr (lexer), &look); - lex_get (lexer); - - if (error) - { - msg (SE, "%s", error); - free (error); - return 0; - } - - pivot_table_look_set_default (look); - pivot_table_look_unref (look); - } - - return 1; -} - -/* Parses the EPOCH subcommand, which controls the epoch used for - parsing 2-digit years. */ -static int -stc_custom_epoch (struct lexer *lexer, - struct dataset *ds UNUSED, - struct cmd_set *cmd UNUSED, void *aux UNUSED) -{ - lex_match (lexer, T_EQUALS); - if (lex_match_id (lexer, "AUTOMATIC")) - settings_set_epoch (-1); - else if (lex_is_integer (lexer)) - { - int new_epoch = lex_integer (lexer); - lex_get (lexer); - if (new_epoch < 1500) - { - msg (SE, _("%s must be 1500 or later."), "EPOCH"); - return 0; - } - settings_set_epoch (new_epoch); - } - else - { - lex_error (lexer, _("expecting %s or year"), "AUTOMATIC"); - return 0; - } - - return 1; -} - -static int -stc_custom_errors (struct lexer *lexer, struct dataset *ds UNUSED, - struct cmd_set *cmd UNUSED, void *aux UNUSED) -{ - return set_output_routing (lexer, SETTINGS_OUTPUT_ERROR); -} - -static int -stc_custom_length (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED) -{ - int page_length; - - lex_match (lexer, T_EQUALS); - if (lex_match_id (lexer, "NONE")) - page_length = -1; - else - { - if (!lex_force_int (lexer)) - return 0; - if (lex_integer (lexer) < 1) - { - msg (SE, _("%s must be at least %d."), "LENGTH", 1); - return 0; - } - page_length = lex_integer (lexer); - lex_get (lexer); - } - - if (page_length != -1) - settings_set_viewlength (page_length); - - return 1; -} - -static int -stc_custom_locale (struct lexer *lexer, struct dataset *ds UNUSED, - struct cmd_set *cmd UNUSED, void *aux UNUSED) -{ - const char *s; - - lex_match (lexer, T_EQUALS); - - if ( !lex_force_string (lexer)) - return 0; - - s = lex_tokcstr (lexer); - - /* First try this string as an encoding name */ - if ( valid_encoding (s)) - set_default_encoding (s); - - /* Now try as a locale name (or alias) */ - else if (set_encoding_from_locale (s)) - { - } - else - { - msg (ME, _("%s is not a recognized encoding or locale name"), s); - return 0; - } - - lex_get (lexer); - - return 1; -} - -static int -stc_custom_messages (struct lexer *lexer, struct dataset *ds UNUSED, - struct cmd_set *cmd UNUSED, void *aux UNUSED) -{ - return set_output_routing (lexer, SETTINGS_OUTPUT_NOTE); -} - -static int -stc_custom_printback (struct lexer *lexer, struct dataset *ds UNUSED, - struct cmd_set *cmd UNUSED, void *aux UNUSED) -{ - return set_output_routing (lexer, SETTINGS_OUTPUT_SYNTAX); -} - -static int -stc_custom_results (struct lexer *lexer, struct dataset *ds UNUSED, - struct cmd_set *cmd UNUSED, void *aux UNUSED) -{ - return set_output_routing (lexer, SETTINGS_OUTPUT_RESULT); -} - -static int -stc_custom_seed (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED) -{ - lex_match (lexer, T_EQUALS); - if (lex_match_id (lexer, "RANDOM")) - set_rng (time (0)); - else - { - if (!lex_force_num (lexer)) - return 0; - set_rng (lex_number (lexer)); - lex_get (lexer); - } - - return 1; -} - -static int -stc_custom_width (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED) -{ - lex_match (lexer, T_EQUALS); - if (lex_match_id (lexer, "NARROW")) - settings_set_viewwidth (79); - else if (lex_match_id (lexer, "WIDE")) - settings_set_viewwidth (131); - else - { - if (!lex_force_int (lexer)) - return 0; - if (lex_integer (lexer) < 40) - { - msg (SE, _("%s must be at least %d."), "WIDTH", 40); - return 0; - } - settings_set_viewwidth (lex_integer (lexer)); - lex_get (lexer); - } - - return 1; -} - -/* Parses FORMAT subcommand, which consists of a numeric format - specifier. */ -static int -stc_custom_format (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED) -{ - struct fmt_spec fmt; - - lex_match (lexer, T_EQUALS); - if (!parse_format_specifier (lexer, &fmt)) - return 0; - - if (!fmt_check_output (&fmt)) - return 0; - - if (fmt_is_string (fmt.type)) - { - char str[FMT_STRING_LEN_MAX + 1]; - msg (SE, _("%s requires numeric output format as an argument. " - "Specified format %s is of type string."), - "FORMAT", - fmt_to_string (&fmt, str)); - return 0; - } - - settings_set_format (&fmt); - return 1; -} - -static int -stc_custom_journal (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED) -{ - lex_match (lexer, T_EQUALS); - if (lex_match_id (lexer, "ON") || lex_match_id (lexer, "YES")) - journal_enable (); - else if (lex_match_id (lexer, "OFF") || lex_match_id (lexer, "NO")) - journal_disable (); - else if (lex_is_string (lexer) || lex_token (lexer) == T_ID) - { - char *filename = utf8_to_filename (lex_tokcstr (lexer)); - journal_set_file_name (filename); - free (filename); - - lex_get (lexer); - } - else - { - lex_error (lexer, NULL); - return 0; - } - return 1; -} - -static int -stc_custom_log (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED) -{ - return stc_custom_journal (lexer, ds, cmd, aux); -} - -static char * -show_output_routing (enum settings_output_type type) -{ - enum settings_output_devices devices; - const char *s; - - devices = settings_get_output_routing (type); - if (devices & SETTINGS_DEVICE_LISTING) - s = devices & SETTINGS_DEVICE_TERMINAL ? "BOTH" : "LISTING"; - else if (devices & SETTINGS_DEVICE_TERMINAL) - s = "TERMINAL"; - else - s = "NONE"; - - return xstrdup (s); -} - -static char * -show_blanks (const struct dataset *ds UNUSED) -{ - return (settings_get_blanks () == SYSMIS - ? xstrdup ("SYSMIS") - : xasprintf ("%.*g", DBL_DIG + 1, settings_get_blanks ())); -} - -static char * -show_cc (enum fmt_type type) -{ - return fmt_number_style_to_string (fmt_settings_get_style ( - settings_get_fmt_settings (), type)); -} - -static char * -show_cca (const struct dataset *ds UNUSED) -{ - return show_cc (FMT_CCA); -} - -static char * -show_ccb (const struct dataset *ds UNUSED) -{ - return show_cc (FMT_CCB); -} - -static char * -show_ccc (const struct dataset *ds UNUSED) -{ - return show_cc (FMT_CCC); -} - -static char * -show_ccd (const struct dataset *ds UNUSED) -{ - return show_cc (FMT_CCD); -} - -static char * -show_cce (const struct dataset *ds UNUSED) -{ - return show_cc (FMT_CCE); -} - -static char * -show_decimals (const struct dataset *ds UNUSED) -{ - return xasprintf ("`%c'", settings_get_fmt_settings ()->decimal); -} - -static char * -show_errors (const struct dataset *ds UNUSED) -{ - return show_output_routing (SETTINGS_OUTPUT_ERROR); -} - -static char * -show_format (const struct dataset *ds UNUSED) -{ - char str[FMT_STRING_LEN_MAX + 1]; - return xstrdup (fmt_to_string (settings_get_format (), str)); -} - -static char * -show_fuzzbits (const struct dataset *ds UNUSED) -{ - return xasprintf ("%d", settings_get_fuzzbits ()); -} - -static char * -show_journal (const struct dataset *ds UNUSED) -{ - return (journal_is_enabled () - ? xasprintf ("\"%s\"", journal_get_file_name ()) - : xstrdup ("disabled")); -} - -static char * -show_length (const struct dataset *ds UNUSED) -{ - return xasprintf ("%d", settings_get_viewlength ()); -} - -static char * -show_locale (const struct dataset *ds UNUSED) -{ - return xstrdup (get_default_encoding ()); -} - -static char * -show_messages (const struct dataset *ds UNUSED) -{ - return show_output_routing (SETTINGS_OUTPUT_NOTE); -} - -static char * -show_printback (const struct dataset *ds UNUSED) -{ - return show_output_routing (SETTINGS_OUTPUT_SYNTAX); -} - -static char * -show_results (const struct dataset *ds UNUSED) -{ - return show_output_routing (SETTINGS_OUTPUT_RESULT); -} - -static char * -show_mxerrs (const struct dataset *ds UNUSED) -{ - return xasprintf ("%d", settings_get_max_messages (MSG_S_ERROR)); -} - -static char * -show_mxloops (const struct dataset *ds UNUSED) -{ - return xasprintf ("%d", settings_get_mxloops ()); -} - -static char * -show_mxwarns (const struct dataset *ds UNUSED) -{ - return xasprintf ("%d", settings_get_max_messages (MSG_S_WARNING)); -} - -/* Returns a name for the given INTEGER_FORMAT value. */ -static char * -show_integer_format (enum integer_format integer_format) -{ - return xasprintf ("%s (%s)", - (integer_format == INTEGER_MSB_FIRST ? "MSBFIRST" - : integer_format == INTEGER_LSB_FIRST ? "LSBFIRST" - : "VAX"), - integer_format == INTEGER_NATIVE ? "NATIVE" : "nonnative"); -} - -/* Returns a name for the given FLOAT_FORMAT value. */ -static char * -show_float_format (enum float_format float_format) -{ - const char *format_name = ""; - - switch (float_format) - { - case FLOAT_IEEE_SINGLE_LE: - format_name = _("ISL (32-bit IEEE 754 single, little-endian)"); - break; - case FLOAT_IEEE_SINGLE_BE: - format_name = _("ISB (32-bit IEEE 754 single, big-endian)"); - break; - case FLOAT_IEEE_DOUBLE_LE: - format_name = _("IDL (64-bit IEEE 754 double, little-endian)"); - break; - case FLOAT_IEEE_DOUBLE_BE: - format_name = _("IDB (64-bit IEEE 754 double, big-endian)"); - break; - - case FLOAT_VAX_F: - format_name = _("VF (32-bit VAX F, VAX-endian)"); - break; - case FLOAT_VAX_D: - format_name = _("VD (64-bit VAX D, VAX-endian)"); - break; - case FLOAT_VAX_G: - format_name = _("VG (64-bit VAX G, VAX-endian)"); - break; - - case FLOAT_Z_SHORT: - format_name = _("ZS (32-bit IBM Z hexadecimal short, big-endian)"); - break; - case FLOAT_Z_LONG: - format_name = _("ZL (64-bit IBM Z hexadecimal long, big-endian)"); - break; - - case FLOAT_FP: - case FLOAT_HEX: - NOT_REACHED (); - } - - return xasprintf ("%s (%s)", format_name, - (float_format == FLOAT_NATIVE_DOUBLE - ? "NATIVE" : "nonnative")); -} - -static char * -show_rib (const struct dataset *ds UNUSED) -{ - return show_integer_format (settings_get_input_integer_format ()); -} - -static char * -show_rrb (const struct dataset *ds UNUSED) -{ - return show_float_format (settings_get_input_float_format ()); -} - -static char * -show_scompression (const struct dataset *ds UNUSED) -{ - return xstrdup (settings_get_scompression () ? "ON" : "OFF"); -} - -static char * -show_undefined (const struct dataset *ds UNUSED) -{ - return xstrdup (settings_get_undefined () ? "WARN" : "NOWARN"); -} - -static char * -show_weight (const struct dataset *ds) -{ - const struct variable *var = dict_get_weight (dataset_dict (ds)); - return xstrdup (var != NULL ? var_get_name (var) : "OFF"); -} - -static char * -show_wib (const struct dataset *ds UNUSED) -{ - return show_integer_format (settings_get_output_integer_format ()); -} - -static char * -show_wrb (const struct dataset *ds UNUSED) -{ - return show_float_format (settings_get_output_float_format ()); -} - -static char * -show_width (const struct dataset *ds UNUSED) -{ - return xasprintf ("%d", settings_get_viewwidth ()); -} - -static char * -show_workspace (const struct dataset *ds UNUSED) -{ - size_t ws = settings_get_workspace () / 1024L; - return xasprintf ("%zu", ws); -} - -static char * -show_current_directory (const struct dataset *ds UNUSED) -{ - char *buf = NULL; - char *wd = NULL; - size_t len = 256; - - do - { - len <<= 1; - buf = xrealloc (buf, len); - } - while (NULL == (wd = getcwd (buf, len))); - - return wd; -} - -static char * -show_tempdir (const struct dataset *ds UNUSED) -{ - return strdup (temp_dir_name ()); -} - -static char * -show_version (const struct dataset *ds UNUSED) -{ - return strdup (announced_version); -} - -static char * -show_system (const struct dataset *ds UNUSED) -{ - return strdup (host_system); -} - -static char * -show_n (const struct dataset *ds) -{ - casenumber n; - size_t l; - - const struct casereader *reader = dataset_source (ds); - - if (reader == NULL) - return strdup (_("Unknown")); - - n = casereader_count_cases (reader); - - return asnprintf (NULL, &l, "%ld", n); -} - - -struct show_sbc - { - const char *name; - char *(*function) (const struct dataset *); - }; - -const struct show_sbc show_table[] = - { - {"BLANKS", show_blanks}, - {"CCA", show_cca}, - {"CCB", show_ccb}, - {"CCC", show_ccc}, - {"CCD", show_ccd}, - {"CCE", show_cce}, - {"DECIMALS", show_decimals}, - {"DIRECTORY", show_current_directory}, - {"ENVIRONMENT", show_system}, - {"ERRORS", show_errors}, - {"FORMAT", show_format}, - {"FUZZBITS", show_fuzzbits}, - {"JOURNAL", show_journal}, - {"LENGTH", show_length}, - {"LOCALE", show_locale}, - {"MESSAGES", show_messages}, - {"MXERRS", show_mxerrs}, - {"MXLOOPS", show_mxloops}, - {"MXWARNS", show_mxwarns}, - {"N", show_n}, - {"PRINTBACk", show_printback}, - {"RESULTS", show_results}, - {"RIB", show_rib}, - {"RRB", show_rrb}, - {"SCOMPRESSION", show_scompression}, - {"TEMPDIR", show_tempdir}, - {"UNDEFINED", show_undefined}, - {"VERSION", show_version}, - {"WEIGHT", show_weight}, - {"WIB", show_wib}, - {"WRB", show_wrb}, - {"WIDTH", show_width}, - {"WORKSPACE", show_workspace}, - }; - -static void -do_show (const struct dataset *ds, const struct show_sbc *sbc) -{ - char *value = sbc->function (ds); - msg (SN, _("%s is %s."), sbc->name, value); - free (value); -} - -static void -show_all (const struct dataset *ds) -{ - size_t i; - - for (i = 0; i < sizeof show_table / sizeof *show_table; i++) - do_show (ds, &show_table[i]); -} - -static void -show_all_cc (const struct dataset *ds) -{ - int i; - - for (i = 0; i < sizeof show_table / sizeof *show_table; i++) - { - const struct show_sbc *sbc = &show_table[i]; - if (!strncmp (sbc->name, "CC", 2)) - do_show (ds, sbc); - } -} - -static void -show_warranty (const struct dataset *ds UNUSED) -{ - fputs (lack_of_warranty, stdout); -} - -static void -show_copying (const struct dataset *ds UNUSED) -{ - fputs (copyleft, stdout); -} - - -int -cmd_show (struct lexer *lexer, struct dataset *ds) -{ - if (lex_token (lexer) == T_ENDCMD) - { - show_all (ds); - return CMD_SUCCESS; - } - - do - { - if (lex_match (lexer, T_ALL)) - show_all (ds); - else if (lex_match_id (lexer, "CC")) - show_all_cc (ds); - else if (lex_match_id (lexer, "WARRANTY")) - show_warranty (ds); - else if (lex_match_id (lexer, "COPYING") || lex_match_id (lexer, "LICENSE")) - show_copying (ds); - else if (lex_token (lexer) == T_ID) - { - int i; - - for (i = 0; i < sizeof show_table / sizeof *show_table; i++) - { - const struct show_sbc *sbc = &show_table[i]; - if (lex_match_id (lexer, sbc->name)) - { - do_show (ds, sbc); - goto found; - } - } - lex_error (lexer, NULL); - return CMD_FAILURE; - - found: ; - } - else - { - lex_error (lexer, NULL); - return CMD_FAILURE; - } - - lex_match (lexer, T_SLASH); - } - while (lex_token (lexer) != T_ENDCMD); - - return CMD_SUCCESS; -} - -#define MAX_SAVED_SETTINGS 5 - -static struct settings *saved_settings[MAX_SAVED_SETTINGS]; -static int n_saved_settings; - -int -cmd_preserve (struct lexer *lexer UNUSED, struct dataset *ds UNUSED) -{ - if (n_saved_settings < MAX_SAVED_SETTINGS) - { - saved_settings[n_saved_settings++] = settings_get (); - return CMD_SUCCESS; - } - else - { - msg (SE, _("Too many %s commands without a %s: at most " - "%d levels of saved settings are allowed."), - "PRESERVE", "RESTORE", - MAX_SAVED_SETTINGS); - return CMD_CASCADING_FAILURE; - } -} - -int -cmd_restore (struct lexer *lexer UNUSED, struct dataset *ds UNUSED) -{ - if (n_saved_settings > 0) - { - struct settings *s = saved_settings[--n_saved_settings]; - settings_set (s); - settings_destroy (s); - return CMD_SUCCESS; - } - else - { - msg (SE, _("%s without matching %s."), "RESTORE", "PRESERVE"); - return CMD_FAILURE; - } -} - -/* - Local Variables: - mode: c - End: -*/