114200cf060d5a4ed0d5adc2c910f2a3e81b0c42
[pspp] / src / data / settings.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011, 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 "data/settings.h"
20
21 #include <assert.h>
22 #include <stdlib.h>
23 #include <time.h>
24
25 #include "data/case.h"
26 #include "data/format.h"
27 #include "data/value.h"
28 #include "libpspp/i18n.h"
29 #include "libpspp/integer-format.h"
30 #include "libpspp/message.h"
31
32 #include "gl/minmax.h"
33 #include "gl/xalloc.h"
34
35 #include "gettext.h"
36 #define _(msgid) gettext (msgid)
37
38 struct settings
39 {
40   /* Integer format used for IB and PIB input. */
41   enum integer_format input_integer_format;
42
43   /* Floating-point format used for RB and RBHEX input. */
44   enum float_format input_float_format;
45
46   /* Format of integers in output (SET WIB). */
47   enum integer_format output_integer_format;
48
49   /* Format of reals in output (SET WRB). */
50   enum float_format output_float_format;
51
52   int viewlength;
53   int viewwidth;
54   bool safer_mode;
55   bool include;
56   int epoch;
57   bool route_errors_to_terminal;
58   bool route_errors_to_listing;
59   bool scompress;
60   bool undefined;
61   double blanks;
62   int max_messages[MSG_N_SEVERITIES];
63   bool printback;
64   bool mprint;
65   int mxloops;
66   size_t workspace;
67   struct fmt_spec default_format;
68   bool testing_mode;
69   int fuzzbits;
70
71   int cmd_algorithm;
72   int global_algorithm;
73   int syntax;
74
75   struct fmt_settings *styles;
76
77   enum settings_output_devices output_routing[SETTINGS_N_OUTPUT_TYPES];
78
79   enum settings_var_style var_output_style;
80   enum settings_value_style value_output_style;
81 };
82
83 static struct settings the_settings = {
84   INTEGER_NATIVE,               /* input_integer_format */
85   FLOAT_NATIVE_DOUBLE,          /* input_float_format */
86   INTEGER_NATIVE,               /* output_integer_format */
87   FLOAT_NATIVE_DOUBLE,          /* output_float_format */
88   24,                           /* viewlength */
89   79,                           /* viewwidth */
90   false,                        /* safer_mode */
91   true,                         /* include */
92   -1,                           /* epoch */
93   true,                         /* route_errors_to_terminal */
94   true,                         /* route_errors_to_listing */
95   true,                         /* scompress */
96   true,                         /* undefined */
97   SYSMIS,                       /* blanks */
98
99   /* max_messages */
100   {
101     100,                        /* MSG_S_ERROR */
102     100,                        /* MSG_S_WARNING */
103     100                         /* MSG_S_NOTE */
104   },
105
106   true,                         /* printback */
107   true,                         /* mprint */
108   40,                           /* mxloops */
109   64L * 1024 * 1024,            /* workspace */
110   {FMT_F, 8, 2},                /* default_format */
111   false,                        /* testing_mode */
112   6,                            /* fuzzbits */
113   ENHANCED,                     /* cmd_algorithm */
114   ENHANCED,                     /* global_algorithm */
115   ENHANCED,                     /* syntax */
116   NULL,                         /* styles */
117
118   /* output_routing */
119   {SETTINGS_DEVICE_LISTING | SETTINGS_DEVICE_TERMINAL,
120    SETTINGS_DEVICE_LISTING | SETTINGS_DEVICE_TERMINAL,
121    0,
122    SETTINGS_DEVICE_LISTING | SETTINGS_DEVICE_TERMINAL},
123
124   SETTINGS_VAR_STYLE_LABELS,
125   SETTINGS_VAL_STYLE_LABELS
126 };
127
128 /* Initializes the settings module. */
129 void
130 settings_init (void)
131 {
132   settings_set_epoch (-1);
133   the_settings.styles = fmt_settings_create ();
134
135   settings_set_decimal_char (get_system_decimal ());
136 }
137
138 /* Cleans up the settings module. */
139 void
140 settings_done (void)
141 {
142   settings_destroy (&the_settings);
143 }
144
145 static void
146 settings_copy (struct settings *dst, const struct settings *src)
147 {
148   *dst = *src;
149   dst->styles = fmt_settings_clone (src->styles);
150 }
151
152 /* Returns a copy of the current settings. */
153 struct settings *
154 settings_get (void)
155 {
156   struct settings *s = xmalloc (sizeof *s);
157   settings_copy (s, &the_settings);
158   return s;
159 }
160
161 /* Replaces the current settings by those in S.  The caller retains ownership
162    of S. */
163 void
164 settings_set (const struct settings *s)
165 {
166   settings_destroy (&the_settings);
167   settings_copy (&the_settings, s);
168 }
169
170 /* Destroys S. */
171 void
172 settings_destroy (struct settings *s)
173 {
174   if (s != NULL)
175     {
176       fmt_settings_destroy (s->styles);
177       if (s != &the_settings)
178         free (s);
179     }
180 }
181
182 /* Returns the floating-point format used for RB and RBHEX
183    input. */
184 enum float_format
185 settings_get_input_float_format (void)
186 {
187   return the_settings.input_float_format;
188 }
189
190 /* Sets the floating-point format used for RB and RBHEX input to
191    FORMAT. */
192 void
193 settings_set_input_float_format ( enum float_format format)
194 {
195   the_settings.input_float_format = format;
196 }
197
198 /* Returns the integer format used for IB and PIB input. */
199 enum integer_format
200 settings_get_input_integer_format (void)
201 {
202   return the_settings.input_integer_format;
203 }
204
205 /* Sets the integer format used for IB and PIB input to
206    FORMAT. */
207 void
208 settings_set_input_integer_format ( enum integer_format format)
209 {
210   the_settings.input_integer_format = format;
211 }
212
213 /* Returns the current output integer format. */
214 enum integer_format
215 settings_get_output_integer_format (void)
216 {
217   return the_settings.output_integer_format;
218 }
219
220 /* Sets the output integer format to INTEGER_FORMAT. */
221 void
222 settings_set_output_integer_format (
223                            enum integer_format integer_format)
224 {
225   the_settings.output_integer_format = integer_format;
226 }
227
228 /* Returns the current output float format. */
229 enum float_format
230 settings_get_output_float_format (void)
231 {
232   return the_settings.output_float_format;
233 }
234
235 /* Sets the output float format to FLOAT_FORMAT. */
236 void
237 settings_set_output_float_format ( enum float_format float_format)
238 {
239   the_settings.output_float_format = float_format;
240 }
241
242 /* Screen length in lines. */
243 int
244 settings_get_viewlength (void)
245 {
246   return the_settings.viewlength;
247 }
248
249 /* Sets the view length. */
250 void
251 settings_set_viewlength ( int viewlength_)
252 {
253   the_settings.viewlength = viewlength_;
254 }
255
256 /* Screen width. */
257 int
258 settings_get_viewwidth(void)
259 {
260   return the_settings.viewwidth;
261 }
262
263 /* Sets the screen width. */
264 void
265 settings_set_viewwidth ( int viewwidth_)
266 {
267   the_settings.viewwidth = viewwidth_;
268 }
269
270 /* Whether PSPP can erase and overwrite files. */
271 bool
272 settings_get_safer_mode (void)
273 {
274   return the_settings.safer_mode;
275 }
276
277 /* Set safer mode. */
278 void
279 settings_set_safer_mode (void)
280 {
281   the_settings.safer_mode = true;
282 }
283
284 /* If echo is on, whether commands from include files are echoed. */
285 bool
286 settings_get_include (void)
287 {
288   return the_settings.include;
289 }
290
291 /* Set include file echo. */
292 void
293 settings_set_include ( bool include)
294 {
295   the_settings.include = include;
296 }
297
298 /* What year to use as the start of the epoch. */
299 int
300 settings_get_epoch (void)
301 {
302   assert (the_settings.epoch >= 0);
303
304   return the_settings.epoch;
305 }
306
307 /* Sets the year that starts the epoch. */
308 void
309 settings_set_epoch ( int epoch)
310 {
311   if (epoch < 0)
312     {
313       time_t t = time (0);
314       struct tm *tm = localtime (&t);
315       epoch = (tm != NULL ? tm->tm_year + 1900 : 2000) - 69;
316     }
317
318   the_settings.epoch = epoch;
319   assert (the_settings.epoch >= 0);
320 }
321
322 /* Compress system files by default? */
323 bool
324 settings_get_scompression (void)
325 {
326   return the_settings.scompress;
327 }
328
329 /* Set system file default compression. */
330 void
331 settings_set_scompression ( bool scompress)
332 {
333   the_settings.scompress = scompress;
334 }
335
336 /* Whether to warn on undefined values in numeric data. */
337 bool
338 settings_get_undefined (void)
339 {
340   return the_settings.undefined;
341 }
342
343 /* Set whether to warn on undefined values. */
344 void
345 settings_set_undefined ( bool undefined)
346 {
347   the_settings.undefined = undefined;
348 }
349
350 /* The value that blank numeric fields are set to when read in. */
351 double
352 settings_get_blanks (void)
353 {
354   return the_settings.blanks;
355 }
356
357 /* Set the value that blank numeric fields are set to when read
358    in. */
359 void
360 settings_set_blanks ( double blanks)
361 {
362   the_settings.blanks = blanks;
363 }
364
365 /* Returns the maximum number of messages to show of the given SEVERITY before
366    aborting.  (The value for MSG_S_WARNING is interpreted as maximum number of
367    warnings and errors combined.) */
368 int
369 settings_get_max_messages (enum msg_severity severity)
370 {
371   assert (severity < MSG_N_SEVERITIES);
372   return the_settings.max_messages[severity];
373 }
374
375 /* Sets the maximum number of messages to show of the given SEVERITY before
376    aborting to MAX.  (The value for MSG_S_WARNING is interpreted as maximum
377    number of warnings and errors combined.)  In addition, in the case of
378    warnings the special value of zero indicates that no warnings are to be
379    issued.
380 */
381 void
382 settings_set_max_messages (enum msg_severity severity, int max)
383 {
384   assert (severity < MSG_N_SEVERITIES);
385
386   if (severity == MSG_S_WARNING)
387     {
388       if ( max == 0)
389         {
390           msg (MW,
391                _("MXWARNS set to zero.  No further warnings will be given even when potentially problematic situations are encountered."));
392           msg_ui_disable_warnings (true);
393         }
394       else if ( the_settings.max_messages [MSG_S_WARNING] == 0)
395         {
396           msg_ui_disable_warnings (false);
397           the_settings.max_messages[MSG_S_WARNING] = max;
398           msg (MW, _("Warnings re-enabled. %d warnings will be issued before aborting syntax processing."), max);
399         }
400     }
401
402   the_settings.max_messages[severity] = max;
403 }
404
405 /* Independent of get_printback, controls whether the commands
406    generated by macro invocations are displayed. */
407 bool
408 settings_get_mprint (void)
409 {
410   return the_settings.mprint;
411 }
412
413 /* Sets whether the commands generated by macro invocations are
414    displayed. */
415 void
416 settings_set_mprint ( bool mprint)
417 {
418   the_settings.mprint = mprint;
419 }
420
421 /* Implied limit of unbounded loop. */
422 int
423 settings_get_mxloops (void)
424 {
425   return the_settings.mxloops;
426 }
427
428 /* Set implied limit of unbounded loop. */
429 void
430 settings_set_mxloops ( int mxloops)
431 {
432   the_settings.mxloops = mxloops;
433 }
434
435 /* Approximate maximum amount of memory to use for cases, in
436    bytes. */
437 size_t
438 settings_get_workspace (void)
439 {
440   return the_settings.workspace;
441 }
442
443 /* Approximate maximum number of cases to allocate in-core, given
444    that each case has the format given in PROTO. */
445 size_t
446 settings_get_workspace_cases (const struct caseproto *proto)
447 {
448   size_t n_cases = settings_get_workspace () / case_get_cost (proto);
449   return MAX (n_cases, 4);
450 }
451
452 /* Set approximate maximum amount of memory to use for cases, in
453    bytes. */
454
455 void
456 settings_set_workspace (size_t workspace)
457 {
458   the_settings.workspace = workspace;
459 }
460
461 /* Default format for variables created by transformations and by
462    DATA LIST {FREE,LIST}. */
463 const struct fmt_spec *
464 settings_get_format (void)
465 {
466   return &the_settings.default_format;
467 }
468
469 /* Set default format for variables created by transformations
470    and by DATA LIST {FREE,LIST}. */
471 void
472 settings_set_format ( const struct fmt_spec *default_format)
473 {
474   the_settings.default_format = *default_format;
475 }
476
477 /* Are we in testing mode?  (e.g. --testing-mode command line
478    option) */
479 bool
480 settings_get_testing_mode (void)
481 {
482   return the_settings.testing_mode;
483 }
484
485 /* Set testing mode. */
486 void
487 settings_set_testing_mode ( bool testing_mode)
488 {
489   the_settings.testing_mode = testing_mode;
490 }
491
492 int
493 settings_get_fuzzbits (void)
494 {
495   return the_settings.fuzzbits;
496 }
497
498 void
499 settings_set_fuzzbits (int fuzzbits)
500 {
501   the_settings.fuzzbits = fuzzbits;
502 }
503
504 /* Return the current algorithm setting */
505 enum behavior_mode
506 settings_get_algorithm (void)
507 {
508   return the_settings.cmd_algorithm;
509 }
510
511 /* Set the algorithm option globally. */
512 void
513 settings_set_algorithm (enum behavior_mode mode)
514 {
515   the_settings.global_algorithm = the_settings.cmd_algorithm = mode;
516 }
517
518 /* Set the algorithm option for this command only */
519 void
520 settings_set_cmd_algorithm ( enum behavior_mode mode)
521 {
522   the_settings.cmd_algorithm = mode;
523 }
524
525 /* Unset the algorithm option for this command */
526 void
527 unset_cmd_algorithm (void)
528 {
529   the_settings.cmd_algorithm = the_settings.global_algorithm;
530 }
531
532 /* Get the current syntax setting */
533 enum behavior_mode
534 settings_get_syntax (void)
535 {
536   return the_settings.syntax;
537 }
538
539 /* Set the syntax option */
540 void
541 settings_set_syntax ( enum behavior_mode mode)
542 {
543   the_settings.syntax = mode;
544 }
545
546 \f
547
548 /* Find the grouping characters in CC_STRING and sets *GROUPING and *DECIMAL
549    appropriately.  Returns true if successful, false otherwise. */
550 static bool
551 find_cc_separators (const char *cc_string, char *decimal, char *grouping)
552 {
553   const char *sp;
554   int comma_cnt, dot_cnt;
555
556   /* Count commas and periods.  There must be exactly three of
557      one or the other, except that an apostrophe escapes a
558      following comma or period. */
559   comma_cnt = dot_cnt = 0;
560   for (sp = cc_string; *sp; sp++)
561     if (*sp == ',')
562       comma_cnt++;
563     else if (*sp == '.')
564       dot_cnt++;
565     else if (*sp == '\'' && (sp[1] == '.' || sp[1] == ',' || sp[1] == '\''))
566       sp++;
567
568   if ((comma_cnt == 3) == (dot_cnt == 3))
569     return false;
570
571   if (comma_cnt == 3)
572     {
573       *decimal = '.';
574       *grouping = ',';
575     }
576   else
577     {
578       *decimal = ',';
579       *grouping = '.';
580     }
581   return true;
582 }
583
584 /* Extracts a token from IN into a newly allocated string AFFIXP.  Tokens are
585    delimited by GROUPING.  Returns the first character following the token. */
586 static const char *
587 extract_cc_token (const char *in, int grouping, char **affixp)
588 {
589   char *out;
590
591   out = *affixp = xmalloc (strlen (in) + 1);
592   for (; *in != '\0' && *in != grouping; in++)
593     {
594       if (*in == '\'' && in[1] == grouping)
595         in++;
596       *out++ = *in;
597     }
598   *out = '\0';
599
600   if (*in == grouping)
601     in++;
602   return in;
603 }
604
605 /* Sets custom currency specifier CC having name CC_NAME ('A' through
606    'E') to correspond to the settings in CC_STRING. */
607 bool
608 settings_set_cc (const char *cc_string, enum fmt_type type)
609 {
610   char *neg_prefix, *prefix, *suffix, *neg_suffix;
611   char decimal, grouping;
612
613   assert (fmt_get_category (type) == FMT_CAT_CUSTOM);
614
615   /* Determine separators. */
616   if (!find_cc_separators (cc_string, &decimal, &grouping))
617     {
618       msg (SE, _("%s: Custom currency string `%s' does not contain "
619                  "exactly three periods or commas (or it contains both)."),
620            fmt_name (type), cc_string);
621       return false;
622     }
623
624   cc_string = extract_cc_token (cc_string, grouping, &neg_prefix);
625   cc_string = extract_cc_token (cc_string, grouping, &prefix);
626   cc_string = extract_cc_token (cc_string, grouping, &suffix);
627   cc_string = extract_cc_token (cc_string, grouping, &neg_suffix);
628
629   fmt_settings_set_style (the_settings.styles, type, decimal, grouping,
630                           neg_prefix, prefix, suffix, neg_suffix);
631
632   free (neg_suffix);
633   free (suffix);
634   free (prefix);
635   free (neg_prefix);
636
637   return true;
638 }
639
640 /* Returns the decimal point character for TYPE. */
641 int
642 settings_get_decimal_char (enum fmt_type type)
643 {
644   return fmt_settings_get_style (the_settings.styles, type)->decimal;
645 }
646
647 void
648 settings_set_decimal_char (char decimal)
649 {
650   fmt_settings_set_decimal (the_settings.styles, decimal);
651 }
652
653 /* Returns the number formatting style associated with the given
654    format TYPE. */
655 const struct fmt_number_style *
656 settings_get_style (enum fmt_type type)
657 {
658   assert (is_fmt_type (type));
659   return fmt_settings_get_style (the_settings.styles, type);
660 }
661
662 /* Returns a string of the form "$#,###.##" according to FMT,
663    which must be of type FMT_DOLLAR.  The caller must free the
664    string. */
665 char *
666 settings_dollar_template (const struct fmt_spec *fmt)
667 {
668   struct string str = DS_EMPTY_INITIALIZER;
669   int c;
670   const struct fmt_number_style *fns ;
671
672   assert (fmt->type == FMT_DOLLAR);
673
674   fns = fmt_settings_get_style (the_settings.styles, fmt->type);
675
676   ds_put_byte (&str, '$');
677   for (c = MAX (fmt->w - fmt->d - 1, 0); c > 0; )
678     {
679       ds_put_byte (&str, '#');
680       if (--c % 4 == 0 && c > 0)
681         {
682           ds_put_byte (&str, fns->grouping);
683           --c;
684         }
685     }
686   if (fmt->d > 0)
687     {
688       ds_put_byte (&str, fns->decimal);
689       ds_put_byte_multiple (&str, '#', fmt->d);
690     }
691
692   return ds_cstr (&str);
693 }
694
695 void
696 settings_set_output_routing (enum settings_output_type type,
697                              enum settings_output_devices devices)
698 {
699   assert (type < SETTINGS_N_OUTPUT_TYPES);
700   the_settings.output_routing[type] = devices;
701 }
702
703 enum settings_output_devices
704 settings_get_output_routing (enum settings_output_type type)
705 {
706   assert (type < SETTINGS_N_OUTPUT_TYPES);
707   return the_settings.output_routing[type] | SETTINGS_DEVICE_UNFILTERED;
708 }
709
710 enum settings_value_style
711 settings_get_value_style (void)
712 {
713   return the_settings.value_output_style;
714 }
715
716 void
717 settings_set_value_style (enum settings_value_style s)
718 {
719   the_settings.value_output_style = s;
720 }
721
722
723
724 enum settings_var_style
725 settings_get_var_style (void)
726 {
727   return the_settings.var_output_style;
728 }
729
730
731 void
732 settings_set_var_style (enum settings_var_style s)
733 {
734   the_settings.var_output_style = s;
735 }