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