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