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