Implemented the SET=TNUMBERS subcommand
[pspp] / src / language / utilities / set.q
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011 Free Software Foundation, Inc.
3
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.
8
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.
13
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/>. */
16
17 #include <config.h>
18
19 #include <stdio.h>
20 #include <errno.h>
21 #include <stdlib.h>
22 #include <time.h>
23
24 #include "data/data-in.h"
25 #include "data/data-out.h"
26 #include "data/dataset.h"
27 #include "data/dictionary.h"
28 #include "data/format.h"
29 #include "data/settings.h"
30 #include "data/value.h"
31 #include "data/variable.h"
32 #include "language/command.h"
33 #include "language/lexer/format-parser.h"
34 #include "language/lexer/lexer.h"
35 #include "libpspp/compiler.h"
36 #include "libpspp/copyleft.h"
37 #include "libpspp/float-format.h"
38 #include "libpspp/i18n.h"
39 #include "libpspp/integer-format.h"
40 #include "libpspp/message.h"
41 #include "math/random.h"
42 #include "output/driver.h"
43 #include "output/journal.h"
44
45 #if HAVE_LIBTERMCAP
46 #if HAVE_TERMCAP_H
47 #include <termcap.h>
48 #else /* !HAVE_TERMCAP_H */
49 int tgetent (char *, const char *);
50 int tgetnum (const char *);
51 #endif /* !HAVE_TERMCAP_H */
52 #endif /* !HAVE_LIBTERMCAP */
53
54 #include "xalloc.h"
55
56 #include "gettext.h"
57 #define _(msgid) gettext (msgid)
58
59 /* (specification)
60    "SET" (stc_):
61      blanks=custom;
62      block=string "x==1" "one character long";
63      boxstring=string "x==3 || x==11" "3 or 11 characters long";
64      case=size:upper/uplow;
65      cca=string;
66      ccb=string;
67      ccc=string;
68      ccd=string;
69      cce=string;
70      compression=compress:on/off;
71      cpi=integer "x>0" "%s must be greater than 0";
72      decimal=dec:dot/comma;
73      epoch=custom;
74      errors=custom;
75      format=custom;
76      headers=headers:no/yes/blank;
77      highres=hires:on/off;
78      histogram=string "x==1" "one character long";
79      include=inc:on/off;
80      journal=custom;
81      log=custom;
82      length=custom;
83      locale=custom;
84      lowres=lores:auto/on/off;
85      lpi=integer "x>0" "%s must be greater than 0";
86      menus=menus:standard/extended;
87      messages=custom;
88      mexpand=mexp:on/off;
89      miterate=integer "x>0" "%s must be greater than 0";
90      mnest=integer "x>0" "%s must be greater than 0";
91      mprint=mprint:on/off;
92      mxerrs=integer "x >= 1" "%s must be at least 1";
93      mxloops=integer "x >=1" "%s must be at least 1";
94      mxmemory=integer;
95      mxwarns=integer;
96      printback=custom;
97      results=custom;
98      rib=rib:msbfirst/lsbfirst/vax/native;
99      rrb=rrb:native/isl/isb/idl/idb/vf/vd/vg/zs/zl;
100      safer=safe:on;
101      scompression=scompress:on/off;
102      scripttab=string "x==1" "one character long";
103      seed=custom;
104      tnumbers=custom;
105      tb1=string "x==3 || x==11" "3 or 11 characters long";
106      tbfonts=string;
107      undefined=undef:warn/nowarn;
108      wib=wib:msbfirst/lsbfirst/vax/native;
109      wrb=wrb:native/isl/isb/idl/idb/vf/vd/vg/zs/zl;
110      width=custom;
111      workspace=integer "x>0" "%s must be positive";
112      xsort=xsort:yes/no.
113 */
114
115 /* (headers) */
116
117 /* (declarations) */
118
119 /* (functions) */
120
121 static enum integer_format stc_to_integer_format (int stc);
122 static enum float_format stc_to_float_format (int stc);
123
124 int
125 cmd_set (struct lexer *lexer, struct dataset *ds)
126 {
127   struct cmd_set cmd;
128
129   if (!parse_set (lexer, ds, &cmd, NULL))
130     {
131       free_set (&cmd);
132       return CMD_FAILURE;
133     }
134
135   if (cmd.sbc_cca)
136     settings_set_cc ( cmd.s_cca, FMT_CCA);
137   if (cmd.sbc_ccb)
138     settings_set_cc ( cmd.s_ccb, FMT_CCB);
139   if (cmd.sbc_ccc)
140     settings_set_cc ( cmd.s_ccc, FMT_CCC);
141   if (cmd.sbc_ccd)
142     settings_set_cc ( cmd.s_ccd, FMT_CCD);
143   if (cmd.sbc_cce)
144     settings_set_cc ( cmd.s_cce, FMT_CCE);
145
146   if (cmd.sbc_decimal)
147     settings_set_decimal_char (cmd.dec == STC_DOT ? '.' : ',');
148
149   if (cmd.sbc_include)
150     settings_set_include (cmd.inc == STC_ON);
151   if (cmd.sbc_mxerrs)
152     settings_set_max_messages (MSG_S_ERROR, cmd.n_mxerrs[0]);
153   if (cmd.sbc_mxwarns)
154     settings_set_max_messages (MSG_S_WARNING, cmd.n_mxwarns[0]);
155   if (cmd.sbc_rib)
156     settings_set_input_integer_format (stc_to_integer_format (cmd.rib));
157   if (cmd.sbc_rrb)
158     settings_set_input_float_format (stc_to_float_format (cmd.rrb));
159   if (cmd.sbc_safer)
160     settings_set_safer_mode ();
161   if (cmd.sbc_scompression)
162     settings_set_scompression (cmd.scompress == STC_ON);
163   if (cmd.sbc_undefined)
164     settings_set_undefined (cmd.undef == STC_WARN);
165   if (cmd.sbc_wib)
166     settings_set_output_integer_format (stc_to_integer_format (cmd.wib));
167   if (cmd.sbc_wrb)
168     settings_set_output_float_format (stc_to_float_format (cmd.wrb));
169   if (cmd.sbc_workspace)
170     {
171       if ( cmd.n_workspace[0] < 1024 && ! settings_get_testing_mode ())
172         msg (SE, _("WORKSPACE must be at least 1MB"));
173       else
174         settings_set_workspace (cmd.n_workspace[0] * 1024L);
175     }
176
177   if (cmd.sbc_block)
178     msg (SW, _("%s is obsolete."), "BLOCK");
179   if (cmd.sbc_boxstring)
180     msg (SW, _("%s is obsolete."), "BOXSTRING");
181   if (cmd.sbc_histogram)
182     msg (SW, _("%s is obsolete."), "HISTOGRAM");
183   if (cmd.sbc_menus)
184     msg (SW, _("%s is obsolete."), "MENUS");
185   if (cmd.sbc_xsort)
186     msg (SW, _("%s is obsolete."), "XSORT");
187   if (cmd.sbc_mxmemory)
188     msg (SE, _("%s is obsolete."), "MXMEMORY");
189   if (cmd.sbc_scripttab)
190     msg (SE, _("%s is obsolete."), "SCRIPTTAB");
191   if (cmd.sbc_tbfonts)
192     msg (SW, _("%s is obsolete."), "TBFONTS");
193   if (cmd.sbc_tb1 && cmd.s_tb1)
194     msg (SW, _("%s is obsolete."), "TB1");
195
196   if (cmd.sbc_case)
197     msg (SW, _("%s is not yet implemented."), "CASE");
198
199   if (cmd.sbc_compression)
200     msg (SW, _("Active file compression is not implemented."));
201
202   free_set (&cmd);
203
204   return CMD_SUCCESS;
205 }
206
207 /* Returns the integer_format value corresponding to STC,
208    which should be the value of cmd.rib or cmd.wib. */
209 static enum integer_format
210 stc_to_integer_format (int stc)
211 {
212   return (stc == STC_MSBFIRST ? INTEGER_MSB_FIRST
213           : stc == STC_LSBFIRST ? INTEGER_LSB_FIRST
214           : stc == STC_VAX ? INTEGER_VAX
215           : INTEGER_NATIVE);
216 }
217
218 /* Returns the float_format value corresponding to STC,
219    which should be the value of cmd.rrb or cmd.wrb. */
220 static enum float_format
221 stc_to_float_format (int stc)
222 {
223   switch (stc)
224     {
225     case STC_NATIVE:
226       return FLOAT_NATIVE_DOUBLE;
227
228     case STC_ISL:
229       return FLOAT_IEEE_SINGLE_LE;
230     case STC_ISB:
231       return FLOAT_IEEE_SINGLE_BE;
232     case STC_IDL:
233       return FLOAT_IEEE_DOUBLE_LE;
234     case STC_IDB:
235       return FLOAT_IEEE_DOUBLE_BE;
236
237     case STC_VF:
238       return FLOAT_VAX_F;
239     case STC_VD:
240       return FLOAT_VAX_D;
241     case STC_VG:
242       return FLOAT_VAX_G;
243
244     case STC_ZS:
245       return FLOAT_Z_SHORT;
246     case STC_ZL:
247       return FLOAT_Z_LONG;
248     }
249
250   NOT_REACHED ();
251 }
252
253 static int
254 set_output_routing (struct lexer *lexer, enum settings_output_type type)
255 {
256   enum settings_output_devices devices;
257
258   lex_match (lexer, T_EQUALS);
259   if (lex_match_id (lexer, "ON") || lex_match_id (lexer, "BOTH"))
260     devices = SETTINGS_DEVICE_LISTING | SETTINGS_DEVICE_TERMINAL;
261   else if (lex_match_id (lexer, "TERMINAL"))
262     devices = SETTINGS_DEVICE_TERMINAL;
263   else if (lex_match_id (lexer, "LISTING"))
264     devices = SETTINGS_DEVICE_LISTING;
265   else if (lex_match_id (lexer, "OFF") || lex_match_id (lexer, "NONE"))
266     devices = 0;
267   else
268     {
269       lex_error (lexer, NULL);
270       return 0;
271     }
272
273   settings_set_output_routing (type, devices);
274
275   return 1;
276 }
277
278 /* Parses the BLANKS subcommand, which controls the value that
279    completely blank fields in numeric data imply.  X, Wnd: Syntax is
280    SYSMIS or a numeric value. */
281 static int
282 stc_custom_blanks (struct lexer *lexer,
283                    struct dataset *ds UNUSED,
284                    struct cmd_set *cmd UNUSED, void *aux UNUSED)
285 {
286   lex_match (lexer, T_EQUALS);
287   if (lex_match_id (lexer, "SYSMIS"))
288     {
289       lex_get (lexer);
290       settings_set_blanks (SYSMIS);
291     }
292   else
293     {
294       if (!lex_force_num (lexer))
295         return 0;
296       settings_set_blanks (lex_number (lexer));
297       lex_get (lexer);
298     }
299   return 1;
300 }
301
302 static int
303 stc_custom_tnumbers (struct lexer *lexer,
304                    struct dataset *ds UNUSED,
305                    struct cmd_set *cmd UNUSED, void *aux UNUSED)
306 {
307   lex_match (lexer, T_EQUALS);
308
309   if (lex_match_id (lexer, "VALUES"))
310     {
311       settings_set_value_style (SETTINGS_VAL_STYLE_VALUES);
312     }
313   else if (lex_match_id (lexer, "LABELS"))
314     {
315       settings_set_value_style (SETTINGS_VAL_STYLE_LABELS);
316     }
317   else if (lex_match_id (lexer, "BOTH"))
318     {
319       settings_set_value_style (SETTINGS_VAL_STYLE_BOTH);
320     }
321   else
322     {
323       lex_error (lexer, _("expecting VALUES, LABELS or BOTH"));
324       return 0;
325     }
326
327   return 1;
328 }
329
330
331 /* Parses the EPOCH subcommand, which controls the epoch used for
332    parsing 2-digit years. */
333 static int
334 stc_custom_epoch (struct lexer *lexer,
335                   struct dataset *ds UNUSED,
336                   struct cmd_set *cmd UNUSED, void *aux UNUSED)
337 {
338   lex_match (lexer, T_EQUALS);
339   if (lex_match_id (lexer, "AUTOMATIC"))
340     settings_set_epoch (-1);
341   else if (lex_is_integer (lexer))
342     {
343       int new_epoch = lex_integer (lexer);
344       lex_get (lexer);
345       if (new_epoch < 1500)
346         {
347           msg (SE, _("EPOCH must be 1500 or later."));
348           return 0;
349         }
350       settings_set_epoch (new_epoch);
351     }
352   else
353     {
354       lex_error (lexer, _("expecting AUTOMATIC or year"));
355       return 0;
356     }
357
358   return 1;
359 }
360
361 static int
362 stc_custom_errors (struct lexer *lexer, struct dataset *ds UNUSED,
363                    struct cmd_set *cmd UNUSED, void *aux UNUSED)
364 {
365   return set_output_routing (lexer, SETTINGS_OUTPUT_ERROR);
366 }
367
368 static int
369 stc_custom_length (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED)
370 {
371   int page_length;
372
373   lex_match (lexer, T_EQUALS);
374   if (lex_match_id (lexer, "NONE"))
375     page_length = -1;
376   else
377     {
378       if (!lex_force_int (lexer))
379         return 0;
380       if (lex_integer (lexer) < 1)
381         {
382           msg (SE, _("LENGTH must be at least 1."));
383           return 0;
384         }
385       page_length = lex_integer (lexer);
386       lex_get (lexer);
387     }
388
389   if (page_length != -1)
390     settings_set_viewlength (page_length);
391
392   return 1;
393 }
394
395 static int
396 stc_custom_locale (struct lexer *lexer, struct dataset *ds UNUSED,
397                    struct cmd_set *cmd UNUSED, void *aux UNUSED)
398 {
399   const char *s;
400
401   lex_match (lexer, T_EQUALS);
402
403   if ( !lex_force_string (lexer))
404     return 0;
405
406   s = lex_tokcstr (lexer);
407
408   /* First try this string as an encoding name */
409   if ( valid_encoding (s))
410     set_default_encoding (s);
411
412   /* Now try as a locale name (or alias) */
413   else if (set_encoding_from_locale (s))
414     {
415     }
416   else
417     {
418       msg (ME, _("%s is not a recognized encoding or locale name"), s);
419       return 0;
420     }
421
422   lex_get (lexer);
423
424   return 1;
425 }
426
427 static int
428 stc_custom_messages (struct lexer *lexer, struct dataset *ds UNUSED,
429                    struct cmd_set *cmd UNUSED, void *aux UNUSED)
430 {
431   return set_output_routing (lexer, SETTINGS_OUTPUT_NOTE);
432 }
433
434 static int
435 stc_custom_printback (struct lexer *lexer, struct dataset *ds UNUSED,
436                       struct cmd_set *cmd UNUSED, void *aux UNUSED)
437 {
438   return set_output_routing (lexer, SETTINGS_OUTPUT_SYNTAX);
439 }
440
441 static int
442 stc_custom_results (struct lexer *lexer, struct dataset *ds UNUSED,
443                     struct cmd_set *cmd UNUSED, void *aux UNUSED)
444 {
445   return set_output_routing (lexer, SETTINGS_OUTPUT_RESULT);
446 }
447
448 static int
449 stc_custom_seed (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED)
450 {
451   lex_match (lexer, T_EQUALS);
452   if (lex_match_id (lexer, "RANDOM"))
453     set_rng (time (0));
454   else
455     {
456       if (!lex_force_num (lexer))
457         return 0;
458       set_rng (lex_number (lexer));
459       lex_get (lexer);
460     }
461
462   return 1;
463 }
464
465 static int
466 stc_custom_width (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED)
467 {
468   lex_match (lexer, T_EQUALS);
469   if (lex_match_id (lexer, "NARROW"))
470     settings_set_viewwidth (79);
471   else if (lex_match_id (lexer, "WIDE"))
472     settings_set_viewwidth (131);
473   else
474     {
475       if (!lex_force_int (lexer))
476         return 0;
477       if (lex_integer (lexer) < 40)
478         {
479           msg (SE, _("WIDTH must be at least 40."));
480           return 0;
481         }
482       settings_set_viewwidth (lex_integer (lexer));
483       lex_get (lexer);
484     }
485
486   return 1;
487 }
488
489 /* Parses FORMAT subcommand, which consists of a numeric format
490    specifier. */
491 static int
492 stc_custom_format (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED)
493 {
494   struct fmt_spec fmt;
495
496   lex_match (lexer, T_EQUALS);
497   if (!parse_format_specifier (lexer, &fmt))
498     return 0;
499
500   if (!fmt_check_output (&fmt))
501     return 0;
502   
503   if (fmt_is_string (fmt.type))
504     {
505       char str[FMT_STRING_LEN_MAX + 1];
506       msg (SE, _("FORMAT requires numeric output format as an argument.  "
507                  "Specified format %s is of type string."),
508            fmt_to_string (&fmt, str));
509       return 0;
510     }
511
512   settings_set_format (&fmt);
513   return 1;
514 }
515
516 static int
517 stc_custom_journal (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED)
518 {
519   lex_match (lexer, T_EQUALS);
520   if (lex_match_id (lexer, "ON") || lex_match_id (lexer, "YES"))
521     journal_enable ();
522   else if (lex_match_id (lexer, "OFF") || lex_match_id (lexer, "NO"))
523     journal_disable ();
524   else if (lex_is_string (lexer) || lex_token (lexer) == T_ID)
525     {
526       char *filename = utf8_to_filename (lex_tokcstr (lexer));
527       journal_set_file_name (filename);
528       free (filename);
529
530       lex_get (lexer);
531     }
532   else
533     {
534       lex_error (lexer, NULL);
535       return 0;
536     }
537   return 1;
538 }
539
540 static int
541 stc_custom_log (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED)
542 {
543   return stc_custom_journal (lexer, ds, cmd, aux);
544 }
545 \f
546 static char *
547 show_output_routing (enum settings_output_type type)
548 {
549   enum settings_output_devices devices;
550   const char *s;
551
552   devices = settings_get_output_routing (type);
553   if (devices & SETTINGS_DEVICE_LISTING)
554     s = devices & SETTINGS_DEVICE_TERMINAL ? "BOTH" : "LISTING";
555   else if (devices & SETTINGS_DEVICE_TERMINAL)
556     s = "TERMINAL";
557   else
558     s = "NONE";
559
560   return xstrdup (s);
561 }
562
563 static char *
564 show_blanks (const struct dataset *ds UNUSED)
565 {
566   return (settings_get_blanks () == SYSMIS
567           ? xstrdup ("SYSMIS")
568           : xasprintf ("%g", settings_get_blanks ()));
569 }
570
571 static void
572 format_cc (struct string *out, const char *in, char grouping)
573 {
574   while (*in != '\0')
575     {
576       char c = *in++;
577       if (c == grouping || c == '\'')
578         ds_put_byte (out, '\'');
579       else if (c == '"')
580         ds_put_byte (out, '"');
581       ds_put_byte (out, c);
582     }
583 }
584
585 static char *
586 show_cc (enum fmt_type type)
587 {
588   const struct fmt_number_style *cc = settings_get_style (type);
589   struct string out;
590
591   ds_init_empty (&out);
592   format_cc (&out, cc->neg_prefix.s, cc->grouping);
593   ds_put_byte (&out, cc->grouping);
594   format_cc (&out, cc->prefix.s, cc->grouping);
595   ds_put_byte (&out, cc->grouping);
596   format_cc (&out, cc->suffix.s, cc->grouping);
597   ds_put_byte (&out, cc->grouping);
598   format_cc (&out, cc->neg_suffix.s, cc->grouping);
599
600   return ds_cstr (&out);
601 }
602
603 static char *
604 show_cca (const struct dataset *ds UNUSED)
605 {
606   return show_cc (FMT_CCA);
607 }
608
609 static char *
610 show_ccb (const struct dataset *ds UNUSED)
611 {
612   return show_cc (FMT_CCB);
613 }
614
615 static char *
616 show_ccc (const struct dataset *ds UNUSED)
617 {
618   return show_cc (FMT_CCC);
619 }
620
621 static char *
622 show_ccd (const struct dataset *ds UNUSED)
623 {
624   return show_cc (FMT_CCD);
625 }
626
627 static char *
628 show_cce (const struct dataset *ds UNUSED)
629 {
630   return show_cc (FMT_CCE);
631 }
632
633 static char *
634 show_decimals (const struct dataset *ds UNUSED)
635 {
636   return xasprintf ("`%c'", settings_get_decimal_char (FMT_F));
637 }
638
639 static char *
640 show_errors (const struct dataset *ds UNUSED)
641 {
642   return show_output_routing (SETTINGS_OUTPUT_ERROR);
643 }
644
645 static char *
646 show_format (const struct dataset *ds UNUSED)
647 {
648   char str[FMT_STRING_LEN_MAX + 1];
649   return xstrdup (fmt_to_string (settings_get_format (), str));
650 }
651
652 static char *
653 show_length (const struct dataset *ds UNUSED)
654 {
655   return xasprintf ("%d", settings_get_viewlength ());
656 }
657
658 static char *
659 show_locale (const struct dataset *ds UNUSED)
660 {
661   return xstrdup (get_default_encoding ());
662 }
663
664 static char *
665 show_messages (const struct dataset *ds UNUSED)
666 {
667   return show_output_routing (SETTINGS_OUTPUT_NOTE);
668 }
669
670 static char *
671 show_printback (const struct dataset *ds UNUSED)
672 {
673   return show_output_routing (SETTINGS_OUTPUT_SYNTAX);
674 }
675
676 static char *
677 show_results (const struct dataset *ds UNUSED)
678 {
679   return show_output_routing (SETTINGS_OUTPUT_RESULT);
680 }
681
682 static char *
683 show_mxerrs (const struct dataset *ds UNUSED)
684 {
685   return xasprintf ("%d", settings_get_max_messages (MSG_S_ERROR));
686 }
687
688 static char *
689 show_mxloops (const struct dataset *ds UNUSED)
690 {
691   return xasprintf ("%d", settings_get_mxloops ());
692 }
693
694 static char *
695 show_mxwarns (const struct dataset *ds UNUSED)
696 {
697   return xasprintf ("%d", settings_get_max_messages (MSG_S_WARNING));
698 }
699
700 /* Returns a name for the given INTEGER_FORMAT value. */
701 static char *
702 show_integer_format (enum integer_format integer_format)
703 {
704   return xasprintf ("%s (%s)",
705                     (integer_format == INTEGER_MSB_FIRST ? "MSBFIRST"
706                      : integer_format == INTEGER_LSB_FIRST ? "LSBFIRST"
707                      : "VAX"),
708                     integer_format == INTEGER_NATIVE ? "NATIVE" : "nonnative");
709 }
710
711 /* Returns a name for the given FLOAT_FORMAT value. */
712 static char *
713 show_float_format (enum float_format float_format)
714 {
715   const char *format_name = "";
716
717   switch (float_format)
718     {
719     case FLOAT_IEEE_SINGLE_LE:
720       format_name = _("ISL (32-bit IEEE 754 single, little-endian)");
721       break;
722     case FLOAT_IEEE_SINGLE_BE:
723       format_name = _("ISB (32-bit IEEE 754 single, big-endian)");
724       break;
725     case FLOAT_IEEE_DOUBLE_LE:
726       format_name = _("IDL (64-bit IEEE 754 double, little-endian)");
727       break;
728     case FLOAT_IEEE_DOUBLE_BE:
729       format_name = _("IDB (64-bit IEEE 754 double, big-endian)");
730       break;
731
732     case FLOAT_VAX_F:
733       format_name = _("VF (32-bit VAX F, VAX-endian)");
734       break;
735     case FLOAT_VAX_D:
736       format_name = _("VD (64-bit VAX D, VAX-endian)");
737       break;
738     case FLOAT_VAX_G:
739       format_name = _("VG (64-bit VAX G, VAX-endian)");
740       break;
741
742     case FLOAT_Z_SHORT:
743       format_name = _("ZS (32-bit IBM Z hexadecimal short, big-endian)");
744       break;
745     case FLOAT_Z_LONG:
746       format_name = _("ZL (64-bit IBM Z hexadecimal long, big-endian)");
747       break;
748
749     case FLOAT_FP:
750     case FLOAT_HEX:
751       NOT_REACHED ();
752     }
753
754   return xasprintf ("%s (%s)", format_name,
755                     (float_format == FLOAT_NATIVE_DOUBLE
756                      ? "NATIVE" : "nonnative"));
757 }
758
759 static char *
760 show_rib (const struct dataset *ds UNUSED)
761 {
762   return show_integer_format (settings_get_input_integer_format ());
763 }
764
765 static char *
766 show_rrb (const struct dataset *ds UNUSED)
767 {
768   return show_float_format (settings_get_input_float_format ());
769 }
770
771 static char *
772 show_scompression (const struct dataset *ds UNUSED)
773 {
774   return xstrdup (settings_get_scompression () ? "ON" : "OFF");
775 }
776
777 static char *
778 show_undefined (const struct dataset *ds UNUSED)
779 {
780   return xstrdup (settings_get_undefined () ? "WARN" : "NOWARN");
781 }
782
783 static char *
784 show_weight (const struct dataset *ds)
785 {
786   const struct variable *var = dict_get_weight (dataset_dict (ds));
787   return xstrdup (var != NULL ? var_get_name (var) : "OFF");
788 }
789
790 static char *
791 show_wib (const struct dataset *ds UNUSED)
792 {
793   return show_integer_format (settings_get_output_integer_format ());
794 }
795
796 static char *
797 show_wrb (const struct dataset *ds UNUSED)
798 {
799   return show_float_format (settings_get_output_float_format ());
800 }
801
802 static char *
803 show_width (const struct dataset *ds UNUSED)
804 {
805   return xasprintf ("%d", settings_get_viewwidth ());
806 }
807
808 struct show_sbc
809   {
810     const char *name;
811     char *(*function) (const struct dataset *);
812   };
813
814 const struct show_sbc show_table[] =
815   {
816     {"BLANKS", show_blanks},
817     {"CCA", show_cca},
818     {"CCB", show_ccb},
819     {"CCC", show_ccc},
820     {"CCD", show_ccd},
821     {"CCE", show_cce},
822     {"DECIMALS", show_decimals},
823     {"ERRORS", show_errors},
824     {"FORMAT", show_format},
825     {"LENGTH", show_length},
826     {"LOCALE", show_locale},
827     {"MESSAGES", show_messages},
828     {"MXERRS", show_mxerrs},
829     {"MXLOOPS", show_mxloops},
830     {"MXWARNS", show_mxwarns},
831     {"PRINTBACk", show_printback},
832     {"RESULTS", show_results},
833     {"RIB", show_rib},
834     {"RRB", show_rrb},
835     {"SCOMPRESSION", show_scompression},
836     {"UNDEFINED", show_undefined},
837     {"WEIGHT", show_weight},
838     {"WIB", show_wib},
839     {"WRB", show_wrb},
840     {"WIDTH", show_width},
841   };
842
843 static void
844 do_show (const struct dataset *ds, const struct show_sbc *sbc)
845 {
846   char *value = sbc->function (ds);
847   msg (SN, _("%s is %s."), sbc->name, value);
848   free (value);
849 }
850
851 static void
852 show_all (const struct dataset *ds)
853 {
854   size_t i;
855
856   for (i = 0; i < sizeof show_table / sizeof *show_table; i++)
857     do_show (ds, &show_table[i]);
858 }
859
860 static void
861 show_all_cc (const struct dataset *ds)
862 {
863   int i;
864
865   for (i = 0; i < sizeof show_table / sizeof *show_table; i++)
866     {
867       const struct show_sbc *sbc = &show_table[i];
868       if (!strncmp (sbc->name, "CC", 2))
869         do_show (ds, sbc);
870     }
871 }
872
873 static void
874 show_warranty (const struct dataset *ds UNUSED)
875 {
876   fputs (lack_of_warranty, stdout);
877 }
878
879 static void
880 show_copying (const struct dataset *ds UNUSED)
881 {
882   fputs (copyleft, stdout);
883 }
884
885 int
886 cmd_show (struct lexer *lexer, struct dataset *ds)
887 {
888   if (lex_token (lexer) == T_ENDCMD)
889     {
890       show_all (ds);
891       return CMD_SUCCESS;
892     }
893
894   do
895     {
896       if (lex_match (lexer, T_ALL))
897         show_all (ds);
898       else if (lex_match_id (lexer, "CC"))
899         show_all_cc (ds);
900       else if (lex_match_id (lexer, "WARRANTY"))
901         show_warranty (ds);
902       else if (lex_match_id (lexer, "COPYING"))
903         show_copying (ds);
904       else if (lex_token (lexer) == T_ID)
905         {
906           int i;
907
908           for (i = 0; i < sizeof show_table / sizeof *show_table; i++)
909             {
910               const struct show_sbc *sbc = &show_table[i];
911               if (lex_match_id (lexer, sbc->name))
912                 {
913                   do_show (ds, sbc);
914                   goto found;
915                 }
916               }
917           lex_error (lexer, NULL);
918           return CMD_FAILURE;
919
920         found: ;
921         }
922       else
923         {
924           lex_error (lexer, NULL);
925           return CMD_FAILURE;
926         }
927
928       lex_match (lexer, T_SLASH);
929     }
930   while (lex_token (lexer) != T_ENDCMD);
931
932   return CMD_SUCCESS;
933 }
934 \f
935 #define MAX_SAVED_SETTINGS 5
936
937 static struct settings *saved_settings[MAX_SAVED_SETTINGS];
938 static int n_saved_settings;
939
940 int
941 cmd_preserve (struct lexer *lexer UNUSED, struct dataset *ds UNUSED)
942 {
943   if (n_saved_settings < MAX_SAVED_SETTINGS)
944     {
945       saved_settings[n_saved_settings++] = settings_get ();
946       return CMD_SUCCESS;
947     }
948   else
949     {
950       msg (SE, _("Too many PRESERVE commands without a RESTORE: at most "
951                  "%d levels of saved settings are allowed."),
952            MAX_SAVED_SETTINGS);
953       return CMD_CASCADING_FAILURE;
954     }
955 }
956
957 int
958 cmd_restore (struct lexer *lexer UNUSED, struct dataset *ds UNUSED)
959 {
960   if (n_saved_settings > 0)
961     {
962       struct settings *s = saved_settings[--n_saved_settings];
963       settings_set (s);
964       settings_destroy (s);
965       return CMD_SUCCESS;
966     }
967   else
968     {
969       msg (SE, _("RESTORE without matching PRESERVE."));
970       return CMD_FAILURE;
971     }
972 }
973
974 /*
975    Local Variables:
976    mode: c
977    End:
978 */