Added new files resulting from directory restructuring.
[pspp-builds.git] / src / language / utilities / set.q
1 /* PSPP - computes sample statistics.
2    Copyright (C) 1997-9, 2000 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 #include "settings.h"
22 #include "message.h"
23 #include <stdio.h>
24 #include <errno.h>
25 #include <stdlib.h>
26 #include <time.h>
27 #include "alloc.h"
28 #include "command.h"
29 #include "dictionary.h"
30 #include "line-buffer.h"
31 #include "lexer.h"
32 #include "message.h"
33 #include "magic.h"
34 #include "output.h"
35 #include "random.h"
36 #include "variable.h"
37 #include "format.h"
38 #include "copyleft.h"
39 #include "variable.h"
40
41
42 #if HAVE_LIBTERMCAP
43 #if HAVE_TERMCAP_H
44 #include <termcap.h>
45 #else /* !HAVE_TERMCAP_H */
46 int tgetent (char *, const char *);
47 int tgetnum (const char *);
48 #endif /* !HAVE_TERMCAP_H */
49 #endif /* !HAVE_LIBTERMCAP */
50
51 #include "gettext.h"
52 #define _(msgid) gettext (msgid)
53
54 /* (specification)
55    "SET" (stc_):
56      blanks=custom;
57      block=string "x==1" "one character long";
58      boxstring=string "x==3 || x==11" "3 or 11 characters long";
59      case=size:upper/uplow;
60      cca=string;
61      ccb=string;
62      ccc=string;
63      ccd=string;
64      cce=string;
65      compression=compress:on/off;
66      cpi=integer "x>0" "%s must be greater than 0";
67      cprompt=string;
68      decimal=dec:dot/comma;
69      disk=custom;
70      dprompt=string;
71      echo=echo:on/off;
72      endcmd=string "x==1" "one character long";
73      epoch=custom;
74      errorbreak=errbrk:on/off;
75      errors=errors:on/off/terminal/listing/both/none;
76      format=custom;
77      headers=headers:no/yes/blank;
78      highres=hires:on/off;
79      histogram=string "x==1" "one character long";
80      include=inc:on/off;
81      journal=custom;
82      length=custom;
83      listing=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=messages:on/off/terminal/listing/both/none;
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      nulline=null:on/off;
97      printback=prtbck:on/off;
98      prompt=string;
99      results=res:on/off/terminal/listing/both/none;
100      safer=safe:on;
101      scompression=scompress:on/off;
102      scripttab=string "x==1" "one character long";
103      seed=custom;
104      tb1=string "x==3 || x==11" "3 or 11 characters long";
105      tbfonts=string;
106      undefined=undef:warn/nowarn;
107      width=custom;
108      workspace=integer "x>=1024" "%s must be at least 1 MB";
109      xsort=xsort:yes/no.
110 */
111
112 /* (declarations) */
113
114 /* (_functions) */
115
116 static bool do_cc (const char *cc_string, int idx);
117
118 int
119 cmd_set (void)
120 {
121   struct cmd_set cmd;
122   bool ok = true;
123
124   if (!parse_set (&cmd))
125     return CMD_FAILURE;
126
127   if (cmd.sbc_cca)
128     ok = ok && do_cc (cmd.s_cca, 0);
129   if (cmd.sbc_ccb)
130     ok = ok && do_cc (cmd.s_ccb, 1);
131   if (cmd.sbc_ccc)
132     ok = ok && do_cc (cmd.s_ccc, 2);
133   if (cmd.sbc_ccd)
134     ok = ok && do_cc (cmd.s_ccd, 3);
135   if (cmd.sbc_cce)
136     ok = ok && do_cc (cmd.s_cce, 4);
137
138   if (cmd.sbc_prompt)
139     getl_set_prompt (GETL_PROMPT_FIRST, cmd.s_prompt);
140   if (cmd.sbc_cprompt)
141     getl_set_prompt (GETL_PROMPT_LATER, cmd.s_cprompt);
142   if (cmd.sbc_dprompt)
143     getl_set_prompt (GETL_PROMPT_DATA, cmd.s_dprompt);
144
145   if (cmd.sbc_decimal)
146     set_decimal (cmd.dec == STC_DOT ? '.' : ',');
147   if (cmd.sbc_echo)
148     set_echo (cmd.echo == STC_ON);
149   if (cmd.sbc_endcmd)
150     set_endcmd (cmd.s_endcmd[0]);
151   if (cmd.sbc_errorbreak)
152     set_errorbreak (cmd.errbrk == STC_ON);
153   if (cmd.sbc_include)
154     set_include (cmd.inc == STC_ON);
155   if (cmd.sbc_mxerrs)
156     set_mxerrs (cmd.n_mxerrs[0]);
157   if (cmd.sbc_mxwarns)
158     set_mxwarns (cmd.n_mxwarns[0]);
159   if (cmd.sbc_nulline)
160     set_nulline (cmd.null == STC_ON);
161   if (cmd.sbc_safer)
162     set_safer_mode ();
163   if (cmd.sbc_scompression)
164     set_scompression (cmd.scompress == STC_ON);
165   if (cmd.sbc_undefined)
166     set_undefined (cmd.undef == STC_WARN);
167   if (cmd.sbc_workspace)
168     set_workspace (cmd.n_workspace[0] * 1024L);
169
170   if (cmd.sbc_block)
171     msg (SW, _("%s is obsolete."),"BLOCK");
172   if (cmd.sbc_boxstring)
173     msg (SW, _("%s is obsolete."),"BOXSTRING");
174   if (cmd.sbc_histogram)
175     msg (MW, _("%s is obsolete."),"HISTOGRAM");
176   if (cmd.sbc_menus )
177     msg (MW, _("%s is obsolete."),"MENUS");
178   if (cmd.sbc_xsort )
179     msg (SW, _("%s is obsolete."),"XSORT");
180   if (cmd.sbc_mxmemory )
181     msg (SE, _("%s is obsolete."),"MXMEMORY");
182   if (cmd.sbc_scripttab)
183     msg (SE, _("%s is obsolete."),"SCRIPTTAB");
184   if (cmd.sbc_tbfonts)
185     msg (SW, _("%s is obsolete."),"TBFONTS");
186   if (cmd.sbc_tb1 && cmd.s_tb1)
187     msg (SW, _("%s is obsolete."),"TB1");
188
189   if (cmd.sbc_case)
190     msg (SW, _("%s is not implemented."), "CASE");
191
192   if (cmd.sbc_compression)
193     msg (MW, _("Active file compression is not implemented."));
194
195   return CMD_SUCCESS;
196 }
197
198 /* Find the grouping characters in CC_STRING and set CC's
199    grouping and decimal members appropriately.  Returns true if
200    successful, false otherwise. */
201 static bool
202 find_cc_separators (const char *cc_string, struct custom_currency *cc)
203 {
204   const char *sp;
205   int comma_cnt, dot_cnt;
206   
207   /* Count commas and periods.  There must be exactly three of
208      one or the other, except that an apostrophe acts escapes a
209      following comma or period. */
210   comma_cnt = dot_cnt = 0;
211   for (sp = cc_string; *sp; sp++)
212     if (*sp == ',')
213       comma_cnt++;
214     else if (*sp == '.')
215       dot_cnt++;
216     else if (*sp == '\'' && (sp[1] == '.' || sp[1] == ',' || sp[1] == '\''))
217       sp++;
218   
219   if ((comma_cnt == 3) == (dot_cnt == 3))
220     return false;
221
222   if (comma_cnt == 3)
223     {
224       cc->decimal = '.';
225       cc->grouping = ',';
226     }
227   else
228     {
229       cc->decimal = ',';
230       cc->grouping = '.';
231     }
232   return true;
233 }
234
235 /* Extracts a token from IN into TOKEn.  Tokens are delimited by
236    GROUPING.  The token is truncated to at most CC_WIDTH
237    characters (including null terminator).  Returns the first
238    character following the token. */
239 static const char *
240 extract_cc_token (const char *in, int grouping, char token[CC_WIDTH]) 
241 {
242   char *out = token;
243   
244   for (; *in != '\0' && *in != grouping; in++) 
245     {
246       if (*in == '\'' && in[1] == grouping)
247         in++;
248       if (out < &token[CC_WIDTH - 1])
249         *out++ = *in;
250     }
251   *out = '\0';
252
253   if (*in == grouping)
254     in++;
255   return in;
256 }
257
258 /* Sets custom currency specifier CC having name CC_NAME ('A' through
259    'E') to correspond to the settings in CC_STRING. */
260 static bool
261 do_cc (const char *cc_string, int idx)
262 {
263   struct custom_currency cc;
264   
265   /* Determine separators. */
266   if (!find_cc_separators (cc_string, &cc)) 
267     {
268       msg (SE, _("CC%c: Custom currency string `%s' does not contain "
269                  "exactly three periods or commas (not both)."),
270            "ABCDE"[idx], cc_string);
271       return false;
272     }
273   
274   cc_string = extract_cc_token (cc_string, cc.grouping, cc.neg_prefix);
275   cc_string = extract_cc_token (cc_string, cc.grouping, cc.prefix);
276   cc_string = extract_cc_token (cc_string, cc.grouping, cc.suffix);
277   cc_string = extract_cc_token (cc_string, cc.grouping, cc.neg_suffix);
278
279   set_cc (idx, &cc);
280   
281   return true;
282 }
283
284 /* Parses the BLANKS subcommand, which controls the value that
285    completely blank fields in numeric data imply.  X, Wnd: Syntax is
286    SYSMIS or a numeric value. */
287 static int
288 stc_custom_blanks (struct cmd_set *cmd UNUSED)
289 {
290   lex_match ('=');
291   if ((token == T_ID && lex_id_match ("SYSMIS", tokid)))
292     {
293       lex_get ();
294       set_blanks (SYSMIS);
295     }
296   else
297     {
298       if (!lex_force_num ())
299         return 0;
300       set_blanks (lex_number ());
301       lex_get ();
302     }
303   return 1;
304 }
305
306 /* Parses the EPOCH subcommand, which controls the epoch used for
307    parsing 2-digit years. */
308 static int
309 stc_custom_epoch (struct cmd_set *cmd UNUSED) 
310 {
311   lex_match ('=');
312   if (lex_match_id ("AUTOMATIC"))
313     set_epoch (-1);
314   else if (lex_is_integer ()) 
315     {
316       int new_epoch = lex_integer ();
317       lex_get ();
318       if (new_epoch < 1500) 
319         {
320           msg (SE, _("EPOCH must be 1500 or later."));
321           return 0;
322         }
323       set_epoch (new_epoch);
324     }
325   else 
326     {
327       lex_error (_("expecting AUTOMATIC or year"));
328       return 0;
329     }
330
331   return 1;
332 }
333
334 static int
335 stc_custom_length (struct cmd_set *cmd UNUSED)
336 {
337   int page_length;
338
339   lex_match ('=');
340   if (lex_match_id ("NONE"))
341     page_length = -1;
342   else
343     {
344       if (!lex_force_int ())
345         return 0;
346       if (lex_integer () < 1)
347         {
348           msg (SE, _("LENGTH must be at least 1."));
349           return 0;
350         }
351       page_length = lex_integer ();
352       lex_get ();
353     }
354
355   if (page_length != -1) 
356     set_viewlength (page_length);
357
358   return 1;
359 }
360
361 static int
362 stc_custom_seed (struct cmd_set *cmd UNUSED)
363 {
364   lex_match ('=');
365   if (lex_match_id ("RANDOM"))
366     set_rng (time (0));
367   else
368     {
369       if (!lex_force_num ())
370         return 0;
371       set_rng (lex_number ());
372       lex_get ();
373     }
374
375   return 1;
376 }
377
378 static int
379 stc_custom_width (struct cmd_set *cmd UNUSED)
380 {
381   lex_match ('=');
382   if (lex_match_id ("NARROW"))
383     set_viewwidth (79);
384   else if (lex_match_id ("WIDE"))
385     set_viewwidth (131);
386   else
387     {
388       if (!lex_force_int ())
389         return 0;
390       if (lex_integer () < 40)
391         {
392           msg (SE, _("WIDTH must be at least 40."));
393           return 0;
394         }
395       set_viewwidth (lex_integer ());
396       lex_get ();
397     }
398
399   return 1;
400 }
401
402 /* Parses FORMAT subcommand, which consists of a numeric format
403    specifier. */
404 static int
405 stc_custom_format (struct cmd_set *cmd UNUSED)
406 {
407   struct fmt_spec fmt;
408
409   lex_match ('=');
410   if (!parse_format_specifier (&fmt, 0))
411     return 0;
412   if ((formats[fmt.type].cat & FCAT_STRING) != 0)
413     {
414       msg (SE, _("FORMAT requires numeric output format as an argument.  "
415                  "Specified format %s is of type string."),
416            fmt_to_string (&fmt));
417       return 0;
418     }
419
420   set_format (&fmt);
421   return 1;
422 }
423
424 static int
425 stc_custom_journal (struct cmd_set *cmd UNUSED)
426 {
427   lex_match ('=');
428   if (!lex_match_id ("ON") && !lex_match_id ("OFF")) 
429     {
430       if (token == T_STRING)
431         lex_get ();
432       else
433         {
434           lex_error (NULL);
435           return 0;
436         }
437     }
438   return 1;
439 }
440
441 static int
442 stc_custom_listing (struct cmd_set *cmd UNUSED)
443 {
444   bool listing;
445
446   lex_match ('=');
447   if (lex_match_id ("ON") || lex_match_id ("YES"))
448     listing = true;
449   else if (lex_match_id ("OFF") || lex_match_id ("NO"))
450     listing = false;
451   else
452     {
453       /* FIXME */
454       return 0;
455     }
456   outp_enable_device (listing, OUTP_DEV_LISTING);
457
458   return 1;
459 }
460
461 static int
462 stc_custom_disk (struct cmd_set *cmd UNUSED)
463 {
464   return stc_custom_listing (cmd);
465 }
466 \f
467 static void
468 show_blanks (void) 
469 {
470   if (get_blanks () == SYSMIS)
471     msg (MM, _("BLANKS is SYSMIS."));
472   else
473     msg (MM, _("BLANKS is %g."), get_blanks ());
474
475 }
476
477 static char *
478 format_cc (const char *in, char grouping, char *out) 
479 {
480   while (*in != '\0') 
481     {
482       if (*in == grouping || *in == '\'')
483         *out++ = '\'';
484       *out++ = *in++;
485     }
486   return out;
487 }
488
489 static void
490 show_cc (int idx) 
491 {
492   const struct custom_currency *cc = get_cc (idx);
493   char cc_string[CC_WIDTH * 4 * 2 + 3 + 1];
494   char *out;
495
496   out = format_cc (cc->neg_prefix, cc->grouping, cc_string);
497   *out++ = cc->grouping;
498   out = format_cc (cc->prefix, cc->grouping, out);
499   *out++ = cc->grouping;
500   out = format_cc (cc->suffix, cc->grouping, out);
501   *out++ = cc->grouping;
502   out = format_cc (cc->neg_suffix, cc->grouping, out);
503   *out = '\0';
504   
505   msg (MM, _("CC%c is \"%s\"."), "ABCDE"[idx], cc_string);
506 }
507
508
509 static void
510 show_cca (void) 
511 {
512   show_cc (0);
513 }
514
515 static void
516 show_ccb (void) 
517 {
518   show_cc (1);
519 }
520
521 static void
522 show_ccc (void) 
523 {
524   show_cc (2);
525 }
526
527 static void
528 show_ccd (void) 
529 {
530   show_cc (3);
531 }
532
533 static void
534 show_cce (void) 
535 {
536   show_cc (4);
537 }
538
539 static void
540 show_decimals (void) 
541 {
542   msg (MM, _("DECIMAL is \"%c\"."), get_decimal ());
543 }
544
545 static void
546 show_endcmd (void) 
547 {
548   msg (MM, _("ENDCMD is \"%c\"."), get_endcmd ());
549 }
550
551 static void
552 show_format (void) 
553 {
554   msg (MM, _("FORMAT is %s."), fmt_to_string (get_format ()));
555 }
556
557 static void
558 show_length (void) 
559 {
560   msg (MM, _("LENGTH is %d."), get_viewlength ());
561 }
562
563 static void
564 show_mxerrs (void) 
565 {
566   msg (MM, _("MXERRS is %d."), get_mxerrs ());
567 }
568
569 static void
570 show_mxloops (void) 
571 {
572   msg (MM, _("MXLOOPS is %d."), get_mxloops ());
573 }
574
575 static void
576 show_mxwarns (void) 
577 {
578   msg (MM, _("MXWARNS is %d."), get_mxwarns ());
579 }
580
581 static void
582 show_scompression (void) 
583 {
584   if (get_scompression ())
585     msg (MM, _("SCOMPRESSION is ON."));
586   else
587     msg (MM, _("SCOMPRESSION is OFF."));
588 }
589
590 static void
591 show_undefined (void) 
592 {
593   if (get_undefined ())
594     msg (MM, _("UNDEFINED is WARN."));
595   else
596     msg (MM, _("UNDEFINED is NOWARN."));
597 }
598
599 static void
600 show_weight (void) 
601 {
602   struct variable *var = dict_get_weight (default_dict);
603   if (var == NULL)
604     msg (MM, _("WEIGHT is off."));
605   else
606     msg (MM, _("WEIGHT is variable %s."), var->name);
607 }
608
609 static void
610 show_width (void) 
611 {
612   msg (MM, _("WIDTH is %d."), get_viewwidth ());
613 }
614
615 struct show_sbc 
616   {
617     const char *name;
618     void (*function) (void);
619   };
620
621 struct show_sbc show_table[] = 
622   {
623     {"BLANKS", show_blanks},
624     {"CCA", show_cca},
625     {"CCB", show_ccb},
626     {"CCC", show_ccc},
627     {"CCD", show_ccd},
628     {"CCE", show_cce},
629     {"DECIMALS", show_decimals},
630     {"ENDCMD", show_endcmd},
631     {"FORMAT", show_format},
632     {"LENGTH", show_length},
633     {"MXERRS", show_mxerrs},
634     {"MXLOOPS", show_mxloops},
635     {"MXWARNS", show_mxwarns},
636     {"SCOMPRESSION", show_scompression},
637     {"UNDEFINED", show_undefined},
638     {"WEIGHT", show_weight},
639     {"WIDTH", show_width},
640   };
641
642 static void
643 show_all (void) 
644 {
645   size_t i;
646   
647   for (i = 0; i < sizeof show_table / sizeof *show_table; i++)
648     show_table[i].function ();
649 }
650
651 static void
652 show_all_cc (void) 
653 {
654   int i;
655
656   for (i = 0; i < 5; i++)
657     show_cc (i);
658 }
659
660 static void
661 show_warranty (void) 
662 {
663   msg (MM, lack_of_warranty);
664 }
665
666 static void
667 show_copying (void) 
668 {
669   msg (MM, copyleft);
670 }
671
672 int
673 cmd_show (void) 
674 {
675   if (token == '.') 
676     {
677       show_all ();
678       return CMD_SUCCESS;
679     }
680
681   do 
682     {
683       if (lex_match (T_ALL))
684         show_all ();
685       else if (lex_match_id ("CC")) 
686         show_all_cc ();
687       else if (lex_match_id ("WARRANTY"))
688         show_warranty ();
689       else if (lex_match_id ("COPYING"))
690         show_copying ();
691       else if (token == T_ID)
692         {
693           int i;
694
695           for (i = 0; i < sizeof show_table / sizeof *show_table; i++)
696             if (lex_match_id (show_table[i].name)) 
697               {
698                 show_table[i].function ();
699                 goto found;
700               }
701           lex_error (NULL);
702           return CMD_PART_SUCCESS_MAYBE;
703
704         found: ;
705         }
706       else 
707         {
708           lex_error (NULL);
709           return CMD_PART_SUCCESS_MAYBE;
710         }
711
712       lex_match ('/');
713     }
714   while (token != '.');
715
716   return CMD_SUCCESS;
717 }
718
719 /*
720    Local Variables:
721    mode: c
722    End:
723 */