Finish converting struct variable to an opaque type. In this
[pspp-builds.git] / src / language / utilities / set.q
1 /* PSPP - computes sample statistics.
2    Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
3    Written by Ben Pfaff <blp@gnu.org>.
4
5    This program is free software; you can redistribute it and/or
6    modify it under the terms of the GNU General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18    02110-1301, USA. */
19
20 #include <config.h>
21
22 #include <stdio.h>
23 #include <errno.h>
24 #include <stdlib.h>
25 #include <time.h>
26
27 #include <data/data-in.h>
28 #include <data/data-out.h>
29 #include <data/dictionary.h>
30 #include <data/format.h>
31 #include <data/procedure.h>
32 #include <data/settings.h>
33 #include <data/value.h>
34 #include <data/variable.h>
35 #include <language/command.h>
36 #include <language/lexer/format-parser.h>
37 #include <language/lexer/lexer.h>
38 #include <language/prompt.h>
39 #include <libpspp/alloc.h>
40 #include <libpspp/compiler.h>
41 #include <libpspp/copyleft.h>
42 #include <libpspp/float-format.h>
43 #include <libpspp/integer-format.h>
44 #include <libpspp/magic.h>
45 #include <libpspp/message.h>
46 #include <math/random.h>
47 #include <output/output.h>
48
49 #if HAVE_LIBTERMCAP
50 #if HAVE_TERMCAP_H
51 #include <termcap.h>
52 #else /* !HAVE_TERMCAP_H */
53 int tgetent (char *, const char *);
54 int tgetnum (const char *);
55 #endif /* !HAVE_TERMCAP_H */
56 #endif /* !HAVE_LIBTERMCAP */
57
58 #include "gettext.h"
59 #define _(msgid) gettext (msgid)
60
61 /* (specification)
62    "SET" (stc_):
63      blanks=custom;
64      block=string "x==1" "one character long";
65      boxstring=string "x==3 || x==11" "3 or 11 characters long";
66      case=size:upper/uplow;
67      cca=string;
68      ccb=string;
69      ccc=string;
70      ccd=string;
71      cce=string;
72      compression=compress:on/off;
73      cpi=integer "x>0" "%s must be greater than 0";
74      cprompt=string;
75      decimal=dec:dot/comma;
76      disk=custom;
77      dprompt=string;
78      echo=echo:on/off;
79      endcmd=string "x==1" "one character long";
80      epoch=custom;
81      errorbreak=errbrk:on/off;
82      errors=errors:terminal/listing/both/on/none/off;
83      format=custom;
84      headers=headers:no/yes/blank;
85      highres=hires:on/off;
86      histogram=string "x==1" "one character long";
87      include=inc:on/off;
88      journal=custom;
89      length=custom;
90      listing=custom;
91      lowres=lores:auto/on/off;
92      lpi=integer "x>0" "%s must be greater than 0";
93      menus=menus:standard/extended;
94      messages=messages:on/off/terminal/listing/both/on/none/off;
95      mexpand=mexp:on/off;
96      miterate=integer "x>0" "%s must be greater than 0";
97      mnest=integer "x>0" "%s must be greater than 0";
98      mprint=mprint:on/off;
99      mxerrs=integer "x >= 1" "%s must be at least 1";
100      mxloops=integer "x >=1" "%s must be at least 1";
101      mxmemory=integer;
102      mxwarns=integer;
103      nulline=null:on/off;
104      printback=prtbck:on/off;
105      prompt=string;
106      results=res:on/off/terminal/listing/both/on/none/off;
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 "x==1" "one character long";
112      seed=custom;
113      tb1=string "x==3 || x==11" "3 or 11 characters long";
114      tbfonts=string;
115      undefined=undef:warn/nowarn;
116      wib=wib:msbfirst/lsbfirst/vax/native;
117      wrb=wrb:native/isl/isb/idl/idb/vf/vd/vg/zs/zl;
118      width=custom;
119      workspace=integer "x>=1024" "%s must be at least 1 MB";
120      xsort=xsort:yes/no.
121 */
122
123 /* (headers) */
124
125 /* (declarations) */
126
127 /* (functions) */
128
129 static bool do_cc (const char *cc_string, enum fmt_type);
130 static enum integer_format stc_to_integer_format (int stc);
131 static enum float_format stc_to_float_format (int stc);
132
133 int
134 cmd_set (struct lexer *lexer, struct dataset *ds)
135 {
136   struct cmd_set cmd;
137
138   if (!parse_set (lexer, ds, &cmd, NULL))
139     {
140       free_set (&cmd);
141       return CMD_FAILURE;
142     }
143
144   if (cmd.sbc_cca)
145     do_cc (cmd.s_cca, FMT_CCA);
146   if (cmd.sbc_ccb)
147     do_cc (cmd.s_ccb, FMT_CCB);
148   if (cmd.sbc_ccc)
149     do_cc (cmd.s_ccc, FMT_CCC);
150   if (cmd.sbc_ccd)
151     do_cc (cmd.s_ccd, FMT_CCD);
152   if (cmd.sbc_cce)
153     do_cc (cmd.s_cce, FMT_CCE);
154
155   if (cmd.sbc_prompt)
156     prompt_set (PROMPT_FIRST, cmd.s_prompt);
157   if (cmd.sbc_cprompt)
158     prompt_set (PROMPT_LATER, cmd.s_cprompt);
159   if (cmd.sbc_dprompt)
160     prompt_set (PROMPT_DATA, cmd.s_dprompt);
161
162   if (cmd.sbc_decimal)
163     fmt_set_decimal (cmd.dec == STC_DOT ? '.' : ',');
164   if (cmd.sbc_echo)
165     set_echo (cmd.echo == STC_ON);
166   if (cmd.sbc_endcmd)
167     set_endcmd (cmd.s_endcmd[0]);
168   if (cmd.sbc_errorbreak)
169     set_errorbreak (cmd.errbrk == STC_ON);
170   if (cmd.sbc_errors)
171     {
172       bool both = cmd.errors == STC_BOTH || cmd.errors == STC_ON;
173       set_error_routing_to_terminal (cmd.errors == STC_TERMINAL || both);
174       set_error_routing_to_listing (cmd.errors == STC_LISTING || both);
175     }
176   if (cmd.sbc_include)
177     set_include (cmd.inc == STC_ON);
178   if (cmd.sbc_mxerrs)
179     set_mxerrs (cmd.n_mxerrs[0]);
180   if (cmd.sbc_mxwarns)
181     set_mxwarns (cmd.n_mxwarns[0]);
182   if (cmd.sbc_nulline)
183     set_nulline (cmd.null == STC_ON);
184   if (cmd.sbc_rib)
185     data_in_set_integer_format (stc_to_integer_format (cmd.rib));
186   if (cmd.sbc_rrb)
187     data_in_set_float_format (stc_to_float_format (cmd.rrb));
188   if (cmd.sbc_safer)
189     set_safer_mode ();
190   if (cmd.sbc_scompression)
191     set_scompression (cmd.scompress == STC_ON);
192   if (cmd.sbc_undefined)
193     set_undefined (cmd.undef == STC_WARN);
194   if (cmd.sbc_wib)
195     data_out_set_integer_format (stc_to_integer_format (cmd.wib));
196   if (cmd.sbc_wrb)
197     data_out_set_float_format (stc_to_float_format (cmd.wrb));
198   if (cmd.sbc_workspace)
199     set_workspace (cmd.n_workspace[0] * 1024L);
200
201   if (cmd.sbc_block)
202     msg (SW, _("%s is obsolete."), "BLOCK");
203   if (cmd.sbc_boxstring)
204     msg (SW, _("%s is obsolete."), "BOXSTRING");
205   if (cmd.sbc_histogram)
206     msg (SW, _("%s is obsolete."), "HISTOGRAM");
207   if (cmd.sbc_menus)
208     msg (SW, _("%s is obsolete."), "MENUS");
209   if (cmd.sbc_xsort)
210     msg (SW, _("%s is obsolete."), "XSORT");
211   if (cmd.sbc_mxmemory)
212     msg (SE, _("%s is obsolete."), "MXMEMORY");
213   if (cmd.sbc_scripttab)
214     msg (SE, _("%s is obsolete."), "SCRIPTTAB");
215   if (cmd.sbc_tbfonts)
216     msg (SW, _("%s is obsolete."), "TBFONTS");
217   if (cmd.sbc_tb1 && cmd.s_tb1)
218     msg (SW, _("%s is obsolete."), "TB1");
219
220   if (cmd.sbc_case)
221     msg (SW, _("%s is not implemented."), "CASE");
222
223   if (cmd.sbc_compression)
224     msg (SW, _("Active file compression is not implemented."));
225
226   free_set (&cmd);
227
228   return CMD_SUCCESS;
229 }
230
231 /* Returns the integer_format value corresponding to STC,
232    which should be the value of cmd.rib or cmd.wib. */
233 static enum integer_format
234 stc_to_integer_format (int stc) 
235 {
236   return (stc == STC_MSBFIRST ? INTEGER_MSB_FIRST
237           : stc == STC_LSBFIRST ? INTEGER_LSB_FIRST
238           : stc == STC_VAX ? INTEGER_VAX
239           : INTEGER_NATIVE);
240 }
241
242 /* Returns the float_format value corresponding to STC,
243    which should be the value of cmd.rrb or cmd.wrb. */
244 static enum float_format
245 stc_to_float_format (int stc) 
246 {
247   switch (stc) 
248     {
249     case STC_NATIVE:
250       return FLOAT_NATIVE_DOUBLE;
251
252     case STC_ISL:
253       return FLOAT_IEEE_SINGLE_LE;
254     case STC_ISB:
255       return FLOAT_IEEE_SINGLE_BE;
256     case STC_IDL:
257       return FLOAT_IEEE_DOUBLE_LE;
258     case STC_IDB:
259       return FLOAT_IEEE_DOUBLE_BE;
260
261     case STC_VF:
262       return FLOAT_VAX_F;
263     case STC_VD:
264       return FLOAT_VAX_D;
265     case STC_VG:
266       return FLOAT_VAX_G;
267
268     case STC_ZS:
269       return FLOAT_Z_SHORT;
270     case STC_ZL:
271       return FLOAT_Z_LONG;
272     }
273
274   NOT_REACHED ();
275 }
276
277 /* Find the grouping characters in CC_STRING and set CC's
278    grouping and decimal members appropriately.  Returns true if
279    successful, false otherwise. */
280 static bool
281 find_cc_separators (const char *cc_string, struct fmt_number_style *cc)
282 {
283   const char *sp;
284   int comma_cnt, dot_cnt;
285   
286   /* Count commas and periods.  There must be exactly three of
287      one or the other, except that an apostrophe escapes a
288      following comma or period. */
289   comma_cnt = dot_cnt = 0;
290   for (sp = cc_string; *sp; sp++)
291     if (*sp == ',')
292       comma_cnt++;
293     else if (*sp == '.')
294       dot_cnt++;
295     else if (*sp == '\'' && (sp[1] == '.' || sp[1] == ',' || sp[1] == '\''))
296       sp++;
297   
298   if ((comma_cnt == 3) == (dot_cnt == 3))
299     return false;
300
301   if (comma_cnt == 3)
302     {
303       cc->decimal = '.';
304       cc->grouping = ',';
305     }
306   else
307     {
308       cc->decimal = ',';
309       cc->grouping = '.';
310     }
311   return true;
312 }
313
314 /* Extracts a token from IN into a newly allocated AFFIX.  Tokens
315    are delimited by GROUPING.  The token is truncated to at most
316    FMT_STYLE_AFFIX_MAX characters.  Returns the first character
317    following the token. */
318 static const char *
319 extract_cc_token (const char *in, int grouping, struct substring *affix) 
320 {
321   size_t ofs = 0;
322   ss_alloc_uninit (affix, FMT_STYLE_AFFIX_MAX);
323   for (; *in != '\0' && *in != grouping; in++) 
324     {
325       if (*in == '\'' && in[1] == grouping)
326         in++;
327       if (ofs < FMT_STYLE_AFFIX_MAX) 
328         ss_data (*affix)[ofs++] = *in;
329     }
330   affix->length = ofs;
331
332   if (*in == grouping)
333     in++;
334   return in;
335 }
336
337 /* Sets custom currency specifier CC having name CC_NAME ('A' through
338    'E') to correspond to the settings in CC_STRING. */
339 static bool
340 do_cc (const char *cc_string, enum fmt_type type)
341 {
342   struct fmt_number_style *cc = fmt_number_style_create ();
343   
344   /* Determine separators. */
345   if (!find_cc_separators (cc_string, cc)) 
346     {
347       fmt_number_style_destroy (cc);
348       msg (SE, _("%s: Custom currency string `%s' does not contain "
349                  "exactly three periods or commas (or it contains both)."),
350            fmt_name (type), cc_string);
351       return false;
352     }
353   
354   cc_string = extract_cc_token (cc_string, cc->grouping, &cc->neg_prefix);
355   cc_string = extract_cc_token (cc_string, cc->grouping, &cc->prefix);
356   cc_string = extract_cc_token (cc_string, cc->grouping, &cc->suffix);
357   cc_string = extract_cc_token (cc_string, cc->grouping, &cc->neg_suffix);
358
359   fmt_set_style (type, cc);
360   
361   return true;
362 }
363
364 /* Parses the BLANKS subcommand, which controls the value that
365    completely blank fields in numeric data imply.  X, Wnd: Syntax is
366    SYSMIS or a numeric value. */
367 static int
368 stc_custom_blanks (struct lexer *lexer, 
369                    struct dataset *ds UNUSED, 
370                    struct cmd_set *cmd UNUSED, void *aux UNUSED)
371 {
372   lex_match (lexer, '=');
373   if (lex_match_id (lexer, "SYSMIS"))
374     {
375       lex_get (lexer);
376       set_blanks (SYSMIS);
377     }
378   else
379     {
380       if (!lex_force_num (lexer))
381         return 0;
382       set_blanks (lex_number (lexer));
383       lex_get (lexer);
384     }
385   return 1;
386 }
387
388 /* Parses the EPOCH subcommand, which controls the epoch used for
389    parsing 2-digit years. */
390 static int
391 stc_custom_epoch (struct lexer *lexer, 
392                   struct dataset *ds UNUSED, 
393                   struct cmd_set *cmd UNUSED, void *aux UNUSED) 
394 {
395   lex_match (lexer, '=');
396   if (lex_match_id (lexer, "AUTOMATIC"))
397     set_epoch (-1);
398   else if (lex_is_integer (lexer)) 
399     {
400       int new_epoch = lex_integer (lexer);
401       lex_get (lexer);
402       if (new_epoch < 1500) 
403         {
404           msg (SE, _("EPOCH must be 1500 or later."));
405           return 0;
406         }
407       set_epoch (new_epoch);
408     }
409   else 
410     {
411       lex_error (lexer, _("expecting AUTOMATIC or year"));
412       return 0;
413     }
414
415   return 1;
416 }
417
418 static int
419 stc_custom_length (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED)
420 {
421   int page_length;
422
423   lex_match (lexer, '=');
424   if (lex_match_id (lexer, "NONE"))
425     page_length = -1;
426   else
427     {
428       if (!lex_force_int (lexer))
429         return 0;
430       if (lex_integer (lexer) < 1)
431         {
432           msg (SE, _("LENGTH must be at least 1."));
433           return 0;
434         }
435       page_length = lex_integer (lexer);
436       lex_get (lexer);
437     }
438
439   if (page_length != -1) 
440     set_viewlength (page_length);
441
442   return 1;
443 }
444
445 static int
446 stc_custom_seed (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED)
447 {
448   lex_match (lexer, '=');
449   if (lex_match_id (lexer, "RANDOM"))
450     set_rng (time (0));
451   else
452     {
453       if (!lex_force_num (lexer))
454         return 0;
455       set_rng (lex_number (lexer));
456       lex_get (lexer);
457     }
458
459   return 1;
460 }
461
462 static int
463 stc_custom_width (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED)
464 {
465   lex_match (lexer, '=');
466   if (lex_match_id (lexer, "NARROW"))
467     set_viewwidth (79);
468   else if (lex_match_id (lexer, "WIDE"))
469     set_viewwidth (131);
470   else
471     {
472       if (!lex_force_int (lexer))
473         return 0;
474       if (lex_integer (lexer) < 40)
475         {
476           msg (SE, _("WIDTH must be at least 40."));
477           return 0;
478         }
479       set_viewwidth (lex_integer (lexer));
480       lex_get (lexer);
481     }
482
483   return 1;
484 }
485
486 /* Parses FORMAT subcommand, which consists of a numeric format
487    specifier. */
488 static int
489 stc_custom_format (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED)
490 {
491   struct fmt_spec fmt;
492
493   lex_match (lexer, '=');
494   if (!parse_format_specifier (lexer, &fmt))
495     return 0;
496   if (fmt_is_string (fmt.type))
497     {
498       char str[FMT_STRING_LEN_MAX + 1];
499       msg (SE, _("FORMAT requires numeric output format as an argument.  "
500                  "Specified format %s is of type string."),
501            fmt_to_string (&fmt, str));
502       return 0;
503     }
504
505   set_format (&fmt);
506   return 1;
507 }
508
509 static int
510 stc_custom_journal (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED)
511 {
512   lex_match (lexer, '=');
513   if (!lex_match_id (lexer, "ON") && !lex_match_id (lexer, "OFF")) 
514     {
515       if (lex_token (lexer) == T_STRING)
516         lex_get (lexer);
517       else
518         {
519           lex_error (lexer, NULL);
520           return 0;
521         }
522     }
523   return 1;
524 }
525
526 static int
527 stc_custom_listing (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED)
528 {
529   bool listing;
530
531   lex_match (lexer, '=');
532   if (lex_match_id (lexer, "ON") || lex_match_id (lexer, "YES"))
533     listing = true;
534   else if (lex_match_id (lexer, "OFF") || lex_match_id (lexer, "NO"))
535     listing = false;
536   else
537     {
538       /* FIXME */
539       return 0;
540     }
541   outp_enable_device (listing, OUTP_DEV_LISTING);
542
543   return 1;
544 }
545
546 static int
547 stc_custom_disk (struct lexer *lexer, struct dataset *ds, struct cmd_set *cmd UNUSED, void *aux)
548 {
549   return stc_custom_listing (lexer, ds, cmd, aux);
550 }
551 \f
552 static void
553 show_blanks (const struct dataset *ds UNUSED) 
554 {
555   if (get_blanks () == SYSMIS)
556     msg (SN, _("BLANKS is SYSMIS."));
557   else
558     msg (SN, _("BLANKS is %g."), get_blanks ());
559
560 }
561
562 static char *
563 format_cc (struct substring in, char grouping, char *out) 
564 {
565   while (!ss_is_empty (in)) 
566     {
567       char c = ss_get_char (&in);
568       if (c == grouping || c == '\'')
569         *out++ = '\'';
570       else if (c == '"')
571         *out++ = '"';
572       *out++ = c;
573     }
574   return out;
575 }
576
577 static void
578 show_cc (enum fmt_type type) 
579 {
580   const struct fmt_number_style *cc = fmt_get_style (type);
581   char cc_string[FMT_STYLE_AFFIX_MAX * 4 * 2 + 3 + 1];
582   char *out;
583
584   out = format_cc (cc->neg_prefix, cc->grouping, cc_string);
585   *out++ = cc->grouping;
586   out = format_cc (cc->prefix, cc->grouping, out);
587   *out++ = cc->grouping;
588   out = format_cc (cc->suffix, cc->grouping, out);
589   *out++ = cc->grouping;
590   out = format_cc (cc->neg_suffix, cc->grouping, out);
591   *out = '\0';
592   
593   msg (SN, _("%s is \"%s\"."), fmt_name (type), cc_string);
594 }
595
596 static void
597 show_cca (const struct dataset *ds UNUSED) 
598 {
599   show_cc (FMT_CCA);
600 }
601
602 static void
603 show_ccb (const struct dataset *ds UNUSED) 
604 {
605   show_cc (FMT_CCB);
606 }
607
608 static void
609 show_ccc (const struct dataset *ds UNUSED) 
610 {
611   show_cc (FMT_CCC);
612 }
613
614 static void
615 show_ccd (const struct dataset *ds UNUSED) 
616 {
617   show_cc (FMT_CCD);
618 }
619
620 static void
621 show_cce (const struct dataset *ds UNUSED) 
622 {
623   show_cc (FMT_CCE);
624 }
625
626 static void
627 show_decimals (const struct dataset *ds UNUSED) 
628 {
629   msg (SN, _("DECIMAL is \"%c\"."), fmt_decimal_char (FMT_F));
630 }
631
632 static void
633 show_endcmd (const struct dataset *ds UNUSED) 
634 {
635   msg (SN, _("ENDCMD is \"%c\"."), get_endcmd ());
636 }
637
638 static void
639 show_errors (const struct dataset *ds UNUSED) 
640 {
641   bool terminal = get_error_routing_to_terminal ();
642   bool listing = get_error_routing_to_listing ();
643   msg (SN, _("ERRORS is \"%s\"."),
644        terminal && listing ? "BOTH"
645        : terminal ? "TERMINAL"
646        : listing ? "LISTING"
647        : "NONE");
648 }
649
650 static void
651 show_format (const struct dataset *ds UNUSED) 
652 {
653   char str[FMT_STRING_LEN_MAX + 1];
654   msg (SN, _("FORMAT is %s."), fmt_to_string (get_format (), str));
655 }
656
657 static void
658 show_length (const struct dataset *ds UNUSED) 
659 {
660   msg (SN, _("LENGTH is %d."), get_viewlength ());
661 }
662
663 static void
664 show_mxerrs (const struct dataset *ds UNUSED) 
665 {
666   msg (SN, _("MXERRS is %d."), get_mxerrs ());
667 }
668
669 static void
670 show_mxloops (const struct dataset *ds UNUSED) 
671 {
672   msg (SN, _("MXLOOPS is %d."), get_mxloops ());
673 }
674
675 static void
676 show_mxwarns (const struct dataset *ds UNUSED) 
677 {
678   msg (SN, _("MXWARNS is %d."), get_mxwarns ());
679 }
680
681 /* Outputs that SETTING has the given INTEGER_FORMAT value. */
682 static void
683 show_integer_format (const char *setting, enum integer_format integer_format) 
684 {
685   msg (SN, _("%s is %s (%s)."),
686        setting,
687        (integer_format == INTEGER_MSB_FIRST ? "MSBFIRST"
688         : integer_format == INTEGER_LSB_FIRST ? "LSBFIRST"
689         : "VAX"),
690        integer_format == INTEGER_NATIVE ? "NATIVE" : "nonnative");
691 }
692
693 /* Outputs that SETTING has the given FLOAT_FORMAT value. */
694 static void
695 show_float_format (const char *setting, enum float_format float_format) 
696 {
697   const char *format_name = "";
698   
699   switch (float_format)
700     {
701     case FLOAT_IEEE_SINGLE_LE:
702       format_name = "ISL (32-bit IEEE 754 single, little-endian)";
703       break;
704     case FLOAT_IEEE_SINGLE_BE:
705       format_name = "ISB (32-bit IEEE 754 single, big-endian)";
706       break;
707     case FLOAT_IEEE_DOUBLE_LE:
708       format_name = "IDL (64-bit IEEE 754 double, little-endian)";
709       break;
710     case FLOAT_IEEE_DOUBLE_BE:
711       format_name = "IDB (64-bit IEEE 754 double, big-endian)";
712       break;
713
714     case FLOAT_VAX_F:
715       format_name = "VF (32-bit VAX F, VAX-endian)";
716       break;
717     case FLOAT_VAX_D:
718       format_name = "VD (64-bit VAX D, VAX-endian)";
719       break;
720     case FLOAT_VAX_G:
721       format_name = "VG (64-bit VAX G, VAX-endian)";
722       break;
723
724     case FLOAT_Z_SHORT:
725       format_name = "ZS (32-bit IBM Z hexadecimal short, big-endian)";
726       break;
727     case FLOAT_Z_LONG:
728       format_name = "ZL (64-bit IBM Z hexadecimal long, big-endian)";
729       break;
730
731     case FLOAT_FP:
732     case FLOAT_HEX:
733       NOT_REACHED ();
734     }
735
736   msg (SN, _("%s is %s (%s)."),
737        setting, format_name,
738        float_format == FLOAT_NATIVE_DOUBLE ? "NATIVE" : "nonnative");
739 }
740
741 static void
742 show_rib (const struct dataset *ds UNUSED) 
743 {
744   show_integer_format ("RIB", data_in_get_integer_format ());
745 }
746
747 static void
748 show_rrb (const struct dataset *ds UNUSED) 
749 {
750   show_float_format ("RRB", data_in_get_float_format ());
751 }
752
753 static void
754 show_scompression (const struct dataset *ds UNUSED) 
755 {
756   if (get_scompression ())
757     msg (SN, _("SCOMPRESSION is ON."));
758   else
759     msg (SN, _("SCOMPRESSION is OFF."));
760 }
761
762 static void
763 show_undefined (const struct dataset *ds UNUSED) 
764 {
765   if (get_undefined ())
766     msg (SN, _("UNDEFINED is WARN."));
767   else
768     msg (SN, _("UNDEFINED is NOWARN."));
769 }
770
771 static void
772 show_weight (const struct dataset *ds) 
773 {
774   struct variable *var = dict_get_weight (dataset_dict (ds));
775   if (var == NULL)
776     msg (SN, _("WEIGHT is off."));
777   else
778     msg (SN, _("WEIGHT is variable %s."), var_get_name (var));
779 }
780
781 static void
782 show_wib (const struct dataset *ds UNUSED) 
783 {
784   show_integer_format ("WIB", data_out_get_integer_format ());
785 }
786
787 static void
788 show_wrb (const struct dataset *ds UNUSED) 
789 {
790   show_float_format ("WRB", data_out_get_float_format ());
791 }
792
793 static void
794 show_width (const struct dataset *ds UNUSED) 
795 {
796   msg (SN, _("WIDTH is %d."), get_viewwidth ());
797 }
798
799 struct show_sbc 
800   {
801     const char *name;
802     void (*function) (const struct dataset *);
803   };
804
805 const struct show_sbc show_table[] = 
806   {
807     {"BLANKS", show_blanks},
808     {"CCA", show_cca},
809     {"CCB", show_ccb},
810     {"CCC", show_ccc},
811     {"CCD", show_ccd},
812     {"CCE", show_cce},
813     {"DECIMALS", show_decimals},
814     {"ENDCMD", show_endcmd},
815     {"ERRORS", show_errors},      
816     {"FORMAT", show_format},
817     {"LENGTH", show_length},
818     {"MXERRS", show_mxerrs},
819     {"MXLOOPS", show_mxloops},
820     {"MXWARNS", show_mxwarns},
821     {"RIB", show_rib},
822     {"RRB", show_rrb},
823     {"SCOMPRESSION", show_scompression},
824     {"UNDEFINED", show_undefined},
825     {"WEIGHT", show_weight},
826     {"WIB", show_wib},
827     {"WRB", show_wrb},
828     {"WIDTH", show_width},
829   };
830
831 static void
832 show_all (const struct dataset *ds) 
833 {
834   size_t i;
835   
836   for (i = 0; i < sizeof show_table / sizeof *show_table; i++)
837     show_table[i].function (ds);
838 }
839
840 static void
841 show_all_cc (void) 
842 {
843   int i;
844
845   for (i = 0; i < 5; i++)
846     show_cc (i);
847 }
848
849 static void
850 show_warranty (const struct dataset *ds UNUSED) 
851 {
852   msg (MN, lack_of_warranty);
853 }
854
855 static void
856 show_copying (const struct dataset *ds UNUSED) 
857 {
858   msg (MN, copyleft);
859 }
860
861 int
862 cmd_show (struct lexer *lexer, struct dataset *ds) 
863 {
864   if (lex_token (lexer) == '.') 
865     {
866       show_all (ds);
867       return CMD_SUCCESS;
868     }
869
870   do 
871     {
872       if (lex_match (lexer, T_ALL))
873         show_all (ds);
874       else if (lex_match_id (lexer, "CC")) 
875         show_all_cc ();
876       else if (lex_match_id (lexer, "WARRANTY"))
877         show_warranty (ds);
878       else if (lex_match_id (lexer, "COPYING"))
879         show_copying (ds);
880       else if (lex_token (lexer) == T_ID)
881         {
882           int i;
883
884           for (i = 0; i < sizeof show_table / sizeof *show_table; i++)
885             if (lex_match_id (lexer, show_table[i].name)) 
886               {
887                 show_table[i].function (ds);
888                 goto found;
889               }
890           lex_error (lexer, NULL);
891           return CMD_FAILURE;
892
893         found: ;
894         }
895       else 
896         {
897           lex_error (lexer, NULL);
898           return CMD_FAILURE;
899         }
900
901       lex_match (lexer, '/');
902     }
903   while (lex_token (lexer) != '.');
904
905   return CMD_SUCCESS;
906 }
907
908 /*
909    Local Variables:
910    mode: c
911    End:
912 */