1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
25 #include "gl/vasnprintf.h"
27 #include "data/casereader.h"
28 #include "data/data-in.h"
29 #include "data/data-out.h"
30 #include "data/dataset.h"
31 #include "data/dictionary.h"
32 #include "data/format.h"
33 #include "data/settings.h"
34 #include "data/value.h"
35 #include "data/variable.h"
36 #include "language/command.h"
37 #include "language/lexer/format-parser.h"
38 #include "language/lexer/lexer.h"
39 #include "libpspp/compiler.h"
40 #include "libpspp/copyleft.h"
41 #include "libpspp/temp-file.h"
42 #include "libpspp/version.h"
43 #include "libpspp/float-format.h"
44 #include "libpspp/i18n.h"
45 #include "libpspp/integer-format.h"
46 #include "libpspp/message.h"
47 #include "math/random.h"
48 #include "output/driver.h"
49 #include "output/journal.h"
54 #else /* !HAVE_TERMCAP_H */
55 int tgetent (char *, const char *);
56 int tgetnum (const char *);
57 #endif /* !HAVE_TERMCAP_H */
58 #endif /* !HAVE_LIBTERMCAP */
63 #define _(msgid) gettext (msgid)
70 case=size:upper/uplow;
76 compression=compress:on/off;
78 decimal=dec:dot/comma;
82 headers=headers:no/yes/blank;
90 lowres=lores:auto/on/off;
92 menus=menus:standard/extended;
104 rib=rib:msbfirst/lsbfirst/vax/native;
105 rrb=rrb:native/isl/isb/idl/idb/vf/vd/vg/zs/zl;
107 scompression=scompress:on/off;
114 undefined=undef:warn/nowarn;
115 wib=wib:msbfirst/lsbfirst/vax/native;
116 wrb=wrb:native/isl/isb/idl/idb/vf/vd/vg/zs/zl;
128 static enum integer_format stc_to_integer_format (int stc);
129 static enum float_format stc_to_float_format (int stc);
132 cmd_set (struct lexer *lexer, struct dataset *ds)
136 if (!parse_set (lexer, ds, &cmd, NULL))
143 settings_set_cc ( cmd.s_cca, FMT_CCA);
145 settings_set_cc ( cmd.s_ccb, FMT_CCB);
147 settings_set_cc ( cmd.s_ccc, FMT_CCC);
149 settings_set_cc ( cmd.s_ccd, FMT_CCD);
151 settings_set_cc ( cmd.s_cce, FMT_CCE);
154 settings_set_decimal_char (cmd.dec == STC_DOT ? '.' : ',');
157 settings_set_include (cmd.inc == STC_ON);
160 if (cmd.n_mxerrs[0] >= 1)
161 settings_set_max_messages (MSG_S_ERROR, cmd.n_mxerrs[0]);
163 msg (SE, _("%s must be at least 1."), "MXERRS");
167 if (cmd.n_mxloops[0] >= 1)
168 settings_set_mxloops (cmd.n_mxloops[0]);
170 msg (SE, _("%s must be at least 1."), "MXLOOPS");
174 if (cmd.n_mxwarns[0] >= 0)
175 settings_set_max_messages (MSG_S_WARNING, cmd.n_mxwarns[0]);
177 msg (SE, _("%s must not be negative."), "MXWARNS");
180 settings_set_input_integer_format (stc_to_integer_format (cmd.rib));
182 settings_set_input_float_format (stc_to_float_format (cmd.rrb));
184 settings_set_safer_mode ();
185 if (cmd.sbc_scompression)
186 settings_set_scompression (cmd.scompress == STC_ON);
187 if (cmd.sbc_undefined)
188 settings_set_undefined (cmd.undef == STC_WARN);
190 settings_set_output_integer_format (stc_to_integer_format (cmd.wib));
192 settings_set_output_float_format (stc_to_float_format (cmd.wrb));
193 if (cmd.sbc_workspace)
195 if ( cmd.n_workspace[0] < 1024 && ! settings_get_testing_mode ())
196 msg (SE, _("WORKSPACE must be at least 1MB"));
197 else if (cmd.n_workspace[0] <= 0)
198 msg (SE, _("WORKSPACE must be positive"));
200 settings_set_workspace (cmd.n_workspace[0] * 1024L);
204 msg (SW, _("%s is obsolete."), "BLOCK");
205 if (cmd.sbc_boxstring)
206 msg (SW, _("%s is obsolete."), "BOXSTRING");
208 msg (SW, _("%s is obsolete."), "CPI");
209 if (cmd.sbc_histogram)
210 msg (SW, _("%s is obsolete."), "HISTOGRAM");
212 msg (SW, _("%s is obsolete."), "LPI");
214 msg (SW, _("%s is obsolete."), "MENUS");
216 msg (SW, _("%s is obsolete."), "XSORT");
217 if (cmd.sbc_mxmemory)
218 msg (SE, _("%s is obsolete."), "MXMEMORY");
219 if (cmd.sbc_scripttab)
220 msg (SE, _("%s is obsolete."), "SCRIPTTAB");
222 msg (SW, _("%s is obsolete."), "TBFONTS");
223 if (cmd.sbc_tb1 && cmd.s_tb1)
224 msg (SW, _("%s is obsolete."), "TB1");
227 msg (SW, _("%s is not yet implemented."), "CASE");
229 if (cmd.sbc_compression)
230 msg (SW, _("Active file compression is not implemented."));
237 /* Returns the integer_format value corresponding to STC,
238 which should be the value of cmd.rib or cmd.wib. */
239 static enum integer_format
240 stc_to_integer_format (int stc)
242 return (stc == STC_MSBFIRST ? INTEGER_MSB_FIRST
243 : stc == STC_LSBFIRST ? INTEGER_LSB_FIRST
244 : stc == STC_VAX ? INTEGER_VAX
248 /* Returns the float_format value corresponding to STC,
249 which should be the value of cmd.rrb or cmd.wrb. */
250 static enum float_format
251 stc_to_float_format (int stc)
256 return FLOAT_NATIVE_DOUBLE;
259 return FLOAT_IEEE_SINGLE_LE;
261 return FLOAT_IEEE_SINGLE_BE;
263 return FLOAT_IEEE_DOUBLE_LE;
265 return FLOAT_IEEE_DOUBLE_BE;
275 return FLOAT_Z_SHORT;
284 set_output_routing (struct lexer *lexer, enum settings_output_type type)
286 enum settings_output_devices devices;
288 lex_match (lexer, T_EQUALS);
289 if (lex_match_id (lexer, "ON") || lex_match_id (lexer, "BOTH"))
290 devices = SETTINGS_DEVICE_LISTING | SETTINGS_DEVICE_TERMINAL;
291 else if (lex_match_id (lexer, "TERMINAL"))
292 devices = SETTINGS_DEVICE_TERMINAL;
293 else if (lex_match_id (lexer, "LISTING"))
294 devices = SETTINGS_DEVICE_LISTING;
295 else if (lex_match_id (lexer, "OFF") || lex_match_id (lexer, "NONE"))
299 lex_error (lexer, NULL);
303 settings_set_output_routing (type, devices);
308 /* Parses the BLANKS subcommand, which controls the value that
309 completely blank fields in numeric data imply. X, Wnd: Syntax is
310 SYSMIS or a numeric value. */
312 stc_custom_blanks (struct lexer *lexer,
313 struct dataset *ds UNUSED,
314 struct cmd_set *cmd UNUSED, void *aux UNUSED)
316 lex_match (lexer, T_EQUALS);
317 if (lex_match_id (lexer, "SYSMIS"))
320 settings_set_blanks (SYSMIS);
324 if (!lex_force_num (lexer))
326 settings_set_blanks (lex_number (lexer));
333 stc_custom_tnumbers (struct lexer *lexer,
334 struct dataset *ds UNUSED,
335 struct cmd_set *cmd UNUSED, void *aux UNUSED)
337 lex_match (lexer, T_EQUALS);
339 if (lex_match_id (lexer, "VALUES"))
341 settings_set_value_style (SETTINGS_VAL_STYLE_VALUES);
343 else if (lex_match_id (lexer, "LABELS"))
345 settings_set_value_style (SETTINGS_VAL_STYLE_LABELS);
347 else if (lex_match_id (lexer, "BOTH"))
349 settings_set_value_style (SETTINGS_VAL_STYLE_BOTH);
353 lex_error_expecting (lexer, "VALUES", "LABELS", "BOTH", NULL_SENTINEL);
362 stc_custom_tvars (struct lexer *lexer,
363 struct dataset *ds UNUSED,
364 struct cmd_set *cmd UNUSED, void *aux UNUSED)
366 lex_match (lexer, T_EQUALS);
368 if (lex_match_id (lexer, "NAMES"))
370 settings_set_var_style (SETTINGS_VAR_STYLE_NAMES);
372 else if (lex_match_id (lexer, "LABELS"))
374 settings_set_var_style (SETTINGS_VAR_STYLE_LABELS);
376 else if (lex_match_id (lexer, "BOTH"))
378 settings_set_var_style (SETTINGS_VAR_STYLE_BOTH);
382 lex_error_expecting (lexer, "NAMES", "LABELS", "BOTH", NULL_SENTINEL);
390 /* Parses the EPOCH subcommand, which controls the epoch used for
391 parsing 2-digit years. */
393 stc_custom_epoch (struct lexer *lexer,
394 struct dataset *ds UNUSED,
395 struct cmd_set *cmd UNUSED, void *aux UNUSED)
397 lex_match (lexer, T_EQUALS);
398 if (lex_match_id (lexer, "AUTOMATIC"))
399 settings_set_epoch (-1);
400 else if (lex_is_integer (lexer))
402 int new_epoch = lex_integer (lexer);
404 if (new_epoch < 1500)
406 msg (SE, _("EPOCH must be 1500 or later."));
409 settings_set_epoch (new_epoch);
413 lex_error (lexer, _("expecting AUTOMATIC or year"));
421 stc_custom_errors (struct lexer *lexer, struct dataset *ds UNUSED,
422 struct cmd_set *cmd UNUSED, void *aux UNUSED)
424 return set_output_routing (lexer, SETTINGS_OUTPUT_ERROR);
428 stc_custom_length (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED)
432 lex_match (lexer, T_EQUALS);
433 if (lex_match_id (lexer, "NONE"))
437 if (!lex_force_int (lexer))
439 if (lex_integer (lexer) < 1)
441 msg (SE, _("LENGTH must be at least 1."));
444 page_length = lex_integer (lexer);
448 if (page_length != -1)
449 settings_set_viewlength (page_length);
455 stc_custom_locale (struct lexer *lexer, struct dataset *ds UNUSED,
456 struct cmd_set *cmd UNUSED, void *aux UNUSED)
460 lex_match (lexer, T_EQUALS);
462 if ( !lex_force_string (lexer))
465 s = lex_tokcstr (lexer);
467 /* First try this string as an encoding name */
468 if ( valid_encoding (s))
469 set_default_encoding (s);
471 /* Now try as a locale name (or alias) */
472 else if (set_encoding_from_locale (s))
477 msg (ME, _("%s is not a recognized encoding or locale name"), s);
487 stc_custom_messages (struct lexer *lexer, struct dataset *ds UNUSED,
488 struct cmd_set *cmd UNUSED, void *aux UNUSED)
490 return set_output_routing (lexer, SETTINGS_OUTPUT_NOTE);
494 stc_custom_printback (struct lexer *lexer, struct dataset *ds UNUSED,
495 struct cmd_set *cmd UNUSED, void *aux UNUSED)
497 return set_output_routing (lexer, SETTINGS_OUTPUT_SYNTAX);
501 stc_custom_results (struct lexer *lexer, struct dataset *ds UNUSED,
502 struct cmd_set *cmd UNUSED, void *aux UNUSED)
504 return set_output_routing (lexer, SETTINGS_OUTPUT_RESULT);
508 stc_custom_seed (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED)
510 lex_match (lexer, T_EQUALS);
511 if (lex_match_id (lexer, "RANDOM"))
515 if (!lex_force_num (lexer))
517 set_rng (lex_number (lexer));
525 stc_custom_width (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED)
527 lex_match (lexer, T_EQUALS);
528 if (lex_match_id (lexer, "NARROW"))
529 settings_set_viewwidth (79);
530 else if (lex_match_id (lexer, "WIDE"))
531 settings_set_viewwidth (131);
534 if (!lex_force_int (lexer))
536 if (lex_integer (lexer) < 40)
538 msg (SE, _("WIDTH must be at least 40."));
541 settings_set_viewwidth (lex_integer (lexer));
548 /* Parses FORMAT subcommand, which consists of a numeric format
551 stc_custom_format (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED)
555 lex_match (lexer, T_EQUALS);
556 if (!parse_format_specifier (lexer, &fmt))
559 if (!fmt_check_output (&fmt))
562 if (fmt_is_string (fmt.type))
564 char str[FMT_STRING_LEN_MAX + 1];
565 msg (SE, _("FORMAT requires numeric output format as an argument. "
566 "Specified format %s is of type string."),
567 fmt_to_string (&fmt, str));
571 settings_set_format (&fmt);
576 stc_custom_journal (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED)
578 lex_match (lexer, T_EQUALS);
579 if (lex_match_id (lexer, "ON") || lex_match_id (lexer, "YES"))
581 else if (lex_match_id (lexer, "OFF") || lex_match_id (lexer, "NO"))
583 else if (lex_is_string (lexer) || lex_token (lexer) == T_ID)
585 char *filename = utf8_to_filename (lex_tokcstr (lexer));
586 journal_set_file_name (filename);
593 lex_error (lexer, NULL);
600 stc_custom_log (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED)
602 return stc_custom_journal (lexer, ds, cmd, aux);
606 show_output_routing (enum settings_output_type type)
608 enum settings_output_devices devices;
611 devices = settings_get_output_routing (type);
612 if (devices & SETTINGS_DEVICE_LISTING)
613 s = devices & SETTINGS_DEVICE_TERMINAL ? "BOTH" : "LISTING";
614 else if (devices & SETTINGS_DEVICE_TERMINAL)
623 show_blanks (const struct dataset *ds UNUSED)
625 return (settings_get_blanks () == SYSMIS
627 : xasprintf ("%g", settings_get_blanks ()));
631 format_cc (struct string *out, const char *in, char grouping)
636 if (c == grouping || c == '\'')
637 ds_put_byte (out, '\'');
639 ds_put_byte (out, '"');
640 ds_put_byte (out, c);
645 show_cc (enum fmt_type type)
647 const struct fmt_number_style *cc = settings_get_style (type);
650 ds_init_empty (&out);
651 format_cc (&out, cc->neg_prefix.s, cc->grouping);
652 ds_put_byte (&out, cc->grouping);
653 format_cc (&out, cc->prefix.s, cc->grouping);
654 ds_put_byte (&out, cc->grouping);
655 format_cc (&out, cc->suffix.s, cc->grouping);
656 ds_put_byte (&out, cc->grouping);
657 format_cc (&out, cc->neg_suffix.s, cc->grouping);
659 return ds_cstr (&out);
663 show_cca (const struct dataset *ds UNUSED)
665 return show_cc (FMT_CCA);
669 show_ccb (const struct dataset *ds UNUSED)
671 return show_cc (FMT_CCB);
675 show_ccc (const struct dataset *ds UNUSED)
677 return show_cc (FMT_CCC);
681 show_ccd (const struct dataset *ds UNUSED)
683 return show_cc (FMT_CCD);
687 show_cce (const struct dataset *ds UNUSED)
689 return show_cc (FMT_CCE);
693 show_decimals (const struct dataset *ds UNUSED)
695 return xasprintf ("`%c'", settings_get_decimal_char (FMT_F));
699 show_errors (const struct dataset *ds UNUSED)
701 return show_output_routing (SETTINGS_OUTPUT_ERROR);
705 show_format (const struct dataset *ds UNUSED)
707 char str[FMT_STRING_LEN_MAX + 1];
708 return xstrdup (fmt_to_string (settings_get_format (), str));
712 show_journal (const struct dataset *ds UNUSED)
714 return (journal_is_enabled ()
715 ? xasprintf ("\"%s\"", journal_get_file_name ())
716 : xstrdup ("disabled"));
720 show_length (const struct dataset *ds UNUSED)
722 return xasprintf ("%d", settings_get_viewlength ());
726 show_locale (const struct dataset *ds UNUSED)
728 return xstrdup (get_default_encoding ());
732 show_messages (const struct dataset *ds UNUSED)
734 return show_output_routing (SETTINGS_OUTPUT_NOTE);
738 show_printback (const struct dataset *ds UNUSED)
740 return show_output_routing (SETTINGS_OUTPUT_SYNTAX);
744 show_results (const struct dataset *ds UNUSED)
746 return show_output_routing (SETTINGS_OUTPUT_RESULT);
750 show_mxerrs (const struct dataset *ds UNUSED)
752 return xasprintf ("%d", settings_get_max_messages (MSG_S_ERROR));
756 show_mxloops (const struct dataset *ds UNUSED)
758 return xasprintf ("%d", settings_get_mxloops ());
762 show_mxwarns (const struct dataset *ds UNUSED)
764 return xasprintf ("%d", settings_get_max_messages (MSG_S_WARNING));
767 /* Returns a name for the given INTEGER_FORMAT value. */
769 show_integer_format (enum integer_format integer_format)
771 return xasprintf ("%s (%s)",
772 (integer_format == INTEGER_MSB_FIRST ? "MSBFIRST"
773 : integer_format == INTEGER_LSB_FIRST ? "LSBFIRST"
775 integer_format == INTEGER_NATIVE ? "NATIVE" : "nonnative");
778 /* Returns a name for the given FLOAT_FORMAT value. */
780 show_float_format (enum float_format float_format)
782 const char *format_name = "";
784 switch (float_format)
786 case FLOAT_IEEE_SINGLE_LE:
787 format_name = _("ISL (32-bit IEEE 754 single, little-endian)");
789 case FLOAT_IEEE_SINGLE_BE:
790 format_name = _("ISB (32-bit IEEE 754 single, big-endian)");
792 case FLOAT_IEEE_DOUBLE_LE:
793 format_name = _("IDL (64-bit IEEE 754 double, little-endian)");
795 case FLOAT_IEEE_DOUBLE_BE:
796 format_name = _("IDB (64-bit IEEE 754 double, big-endian)");
800 format_name = _("VF (32-bit VAX F, VAX-endian)");
803 format_name = _("VD (64-bit VAX D, VAX-endian)");
806 format_name = _("VG (64-bit VAX G, VAX-endian)");
810 format_name = _("ZS (32-bit IBM Z hexadecimal short, big-endian)");
813 format_name = _("ZL (64-bit IBM Z hexadecimal long, big-endian)");
821 return xasprintf ("%s (%s)", format_name,
822 (float_format == FLOAT_NATIVE_DOUBLE
823 ? "NATIVE" : "nonnative"));
827 show_rib (const struct dataset *ds UNUSED)
829 return show_integer_format (settings_get_input_integer_format ());
833 show_rrb (const struct dataset *ds UNUSED)
835 return show_float_format (settings_get_input_float_format ());
839 show_scompression (const struct dataset *ds UNUSED)
841 return xstrdup (settings_get_scompression () ? "ON" : "OFF");
845 show_undefined (const struct dataset *ds UNUSED)
847 return xstrdup (settings_get_undefined () ? "WARN" : "NOWARN");
851 show_weight (const struct dataset *ds)
853 const struct variable *var = dict_get_weight (dataset_dict (ds));
854 return xstrdup (var != NULL ? var_get_name (var) : "OFF");
858 show_wib (const struct dataset *ds UNUSED)
860 return show_integer_format (settings_get_output_integer_format ());
864 show_wrb (const struct dataset *ds UNUSED)
866 return show_float_format (settings_get_output_float_format ());
870 show_width (const struct dataset *ds UNUSED)
872 return xasprintf ("%d", settings_get_viewwidth ());
876 show_workspace (const struct dataset *ds UNUSED)
878 size_t ws = settings_get_workspace () / 1024L;
879 return xasprintf ("%zu", ws);
883 show_current_directory (const struct dataset *ds UNUSED)
892 buf = xrealloc (buf, len);
894 while (NULL == (wd = getcwd (buf, len)));
900 show_tempdir (const struct dataset *ds UNUSED)
902 return strdup (temp_dir_name ());
906 show_version (const struct dataset *ds UNUSED)
908 return strdup (version);
912 show_system (const struct dataset *ds UNUSED)
914 return strdup (host_system);
918 show_n (const struct dataset *ds)
923 const struct casereader *reader = dataset_source (ds);
926 return strdup (_("Unknown"));
928 n = casereader_count_cases (reader);
930 return asnprintf (NULL, &l, "%ld", n);
937 char *(*function) (const struct dataset *);
940 const struct show_sbc show_table[] =
942 {"BLANKS", show_blanks},
948 {"DECIMALS", show_decimals},
949 {"DIRECTORY", show_current_directory},
950 {"ENVIRONMENT", show_system},
951 {"ERRORS", show_errors},
952 {"FORMAT", show_format},
953 {"JOURNAL", show_journal},
954 {"LENGTH", show_length},
955 {"LOCALE", show_locale},
956 {"MESSAGES", show_messages},
957 {"MXERRS", show_mxerrs},
958 {"MXLOOPS", show_mxloops},
959 {"MXWARNS", show_mxwarns},
961 {"PRINTBACk", show_printback},
962 {"RESULTS", show_results},
965 {"SCOMPRESSION", show_scompression},
966 {"TEMPDIR", show_tempdir},
967 {"UNDEFINED", show_undefined},
968 {"VERSION", show_version},
969 {"WEIGHT", show_weight},
972 {"WIDTH", show_width},
973 {"WORKSPACE", show_workspace},
977 do_show (const struct dataset *ds, const struct show_sbc *sbc)
979 char *value = sbc->function (ds);
980 msg (SN, _("%s is %s."), sbc->name, value);
985 show_all (const struct dataset *ds)
989 for (i = 0; i < sizeof show_table / sizeof *show_table; i++)
990 do_show (ds, &show_table[i]);
994 show_all_cc (const struct dataset *ds)
998 for (i = 0; i < sizeof show_table / sizeof *show_table; i++)
1000 const struct show_sbc *sbc = &show_table[i];
1001 if (!strncmp (sbc->name, "CC", 2))
1007 show_warranty (const struct dataset *ds UNUSED)
1009 fputs (lack_of_warranty, stdout);
1013 show_copying (const struct dataset *ds UNUSED)
1015 fputs (copyleft, stdout);
1020 cmd_show (struct lexer *lexer, struct dataset *ds)
1022 if (lex_token (lexer) == T_ENDCMD)
1030 if (lex_match (lexer, T_ALL))
1032 else if (lex_match_id (lexer, "CC"))
1034 else if (lex_match_id (lexer, "WARRANTY"))
1036 else if (lex_match_id (lexer, "COPYING") || lex_match_id (lexer, "LICENSE"))
1038 else if (lex_token (lexer) == T_ID)
1042 for (i = 0; i < sizeof show_table / sizeof *show_table; i++)
1044 const struct show_sbc *sbc = &show_table[i];
1045 if (lex_match_id (lexer, sbc->name))
1051 lex_error (lexer, NULL);
1058 lex_error (lexer, NULL);
1062 lex_match (lexer, T_SLASH);
1064 while (lex_token (lexer) != T_ENDCMD);
1069 #define MAX_SAVED_SETTINGS 5
1071 static struct settings *saved_settings[MAX_SAVED_SETTINGS];
1072 static int n_saved_settings;
1075 cmd_preserve (struct lexer *lexer UNUSED, struct dataset *ds UNUSED)
1077 if (n_saved_settings < MAX_SAVED_SETTINGS)
1079 saved_settings[n_saved_settings++] = settings_get ();
1084 msg (SE, _("Too many PRESERVE commands without a RESTORE: at most "
1085 "%d levels of saved settings are allowed."),
1086 MAX_SAVED_SETTINGS);
1087 return CMD_CASCADING_FAILURE;
1092 cmd_restore (struct lexer *lexer UNUSED, struct dataset *ds UNUSED)
1094 if (n_saved_settings > 0)
1096 struct settings *s = saved_settings[--n_saved_settings];
1098 settings_destroy (s);
1103 msg (SE, _("RESTORE without matching PRESERVE."));