34649de73c3ed54d44e712afba1efc6dcfbc795a
[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 /* Sets the year that starts the epoch. */
309 void
310 settings_set_epoch (int epoch)
311 {
312   the_settings.styles.epoch = epoch;
313 }
314
315 /* Compress system files by default? */
316 bool
317 settings_get_scompression (void)
318 {
319   return the_settings.scompress;
320 }
321
322 /* Set system file default compression. */
323 void
324 settings_set_scompression (bool scompress)
325 {
326   the_settings.scompress = scompress;
327 }
328
329 /* Whether to warn on undefined values in numeric data. */
330 bool
331 settings_get_undefined (void)
332 {
333   return the_settings.undefined;
334 }
335
336 /* Set whether to warn on undefined values. */
337 void
338 settings_set_undefined (bool undefined)
339 {
340   the_settings.undefined = undefined;
341 }
342
343 /* The value that blank numeric fields are set to when read in. */
344 double
345 settings_get_blanks (void)
346 {
347   return the_settings.blanks;
348 }
349
350 /* Set the value that blank numeric fields are set to when read
351    in. */
352 void
353 settings_set_blanks (double blanks)
354 {
355   the_settings.blanks = blanks;
356 }
357
358 /* Returns the maximum number of messages to show of the given SEVERITY before
359    aborting.  (The value for MSG_S_WARNING is interpreted as maximum number of
360    warnings and errors combined.) */
361 int
362 settings_get_max_messages (enum msg_severity severity)
363 {
364   assert (severity < MSG_N_SEVERITIES);
365   return the_settings.max_messages[severity];
366 }
367
368 /* Sets the maximum number of messages to show of the given SEVERITY before
369    aborting to MAX.  (The value for MSG_S_WARNING is interpreted as maximum
370    number of warnings and errors combined.)  In addition, in the case of
371    warnings the special value of zero indicates that no warnings are to be
372    issued.
373 */
374 void
375 settings_set_max_messages (enum msg_severity severity, int max)
376 {
377   assert (severity < MSG_N_SEVERITIES);
378
379   if (severity == MSG_S_WARNING)
380     {
381       if (max == 0)
382         {
383           msg (MW,
384                _("MXWARNS set to zero.  No further warnings will be given even when potentially problematic situations are encountered."));
385           msg_ui_disable_warnings (true);
386         }
387       else if (the_settings.max_messages [MSG_S_WARNING] == 0)
388         {
389           msg_ui_disable_warnings (false);
390           the_settings.max_messages[MSG_S_WARNING] = max;
391           msg (MW, _("Warnings re-enabled. %d warnings will be issued before aborting syntax processing."), max);
392         }
393     }
394
395   the_settings.max_messages[severity] = max;
396 }
397
398 /* Returns whether to expand macro invocations. */
399 bool
400 settings_get_mexpand (void)
401 {
402   return the_settings.mexpand;
403 }
404
405 /* Sets whether to expand macro invocations. */
406 void
407 settings_set_mexpand (bool mexpand)
408 {
409   the_settings.mexpand = mexpand;
410 }
411
412 /* Independent of get_printback, controls whether the commands
413    generated by macro invocations are displayed. */
414 bool
415 settings_get_mprint (void)
416 {
417   return the_settings.mprint;
418 }
419
420 /* Sets whether the commands generated by macro invocations are
421    displayed. */
422 void
423 settings_set_mprint (bool mprint)
424 {
425   the_settings.mprint = mprint;
426 }
427
428 /* Returns the limit for loop iterations within a macro. */
429 int
430 settings_get_miterate (void)
431 {
432   return the_settings.miterate;
433 }
434
435 /* Sets the limit for loop iterations within a macro. */
436 void
437 settings_set_miterate (int miterate)
438 {
439   the_settings.miterate = miterate;
440 }
441
442 /* Returns the limit for recursion macro expansions. */
443 int settings_get_mnest (void)
444 {
445   return the_settings.mnest;
446 }
447
448 /* Sets the limit for recursion macro expansions. */
449 void
450 settings_set_mnest (int mnest)
451 {
452   the_settings.mnest = mnest;
453 }
454
455 int settings_get_mxloops (void);
456 void settings_set_mxloops (int);
457 /* Implied limit of unbounded loop. */
458 int
459 settings_get_mxloops (void)
460 {
461   return the_settings.mxloops;
462 }
463
464 /* Set implied limit of unbounded loop. */
465 void
466 settings_set_mxloops (int mxloops)
467 {
468   the_settings.mxloops = mxloops;
469 }
470
471 /* Approximate maximum amount of memory to use for cases, in
472    bytes. */
473 size_t
474 settings_get_workspace (void)
475 {
476   return the_settings.workspace;
477 }
478
479 /* Approximate maximum number of cases to allocate in-core, given
480    that each case has the format given in PROTO. */
481 size_t
482 settings_get_workspace_cases (const struct caseproto *proto)
483 {
484   size_t n_cases = settings_get_workspace () / case_get_cost (proto);
485   return MAX (n_cases, 4);
486 }
487
488 /* Set approximate maximum amount of memory to use for cases, in
489    bytes. */
490
491 void
492 settings_set_workspace (size_t workspace)
493 {
494   the_settings.workspace = workspace;
495 }
496
497 /* Default format for variables created by transformations and by
498    DATA LIST {FREE,LIST}. */
499 const struct fmt_spec *
500 settings_get_format (void)
501 {
502   return &the_settings.default_format;
503 }
504
505 /* Set default format for variables created by transformations
506    and by DATA LIST {FREE,LIST}. */
507 void
508 settings_set_format (const struct fmt_spec *default_format)
509 {
510   the_settings.default_format = *default_format;
511 }
512
513 /* Are we in testing mode?  (e.g. --testing-mode command line
514    option) */
515 bool
516 settings_get_testing_mode (void)
517 {
518   return the_settings.testing_mode;
519 }
520
521 /* Set testing mode. */
522 void
523 settings_set_testing_mode (bool testing_mode)
524 {
525   the_settings.testing_mode = testing_mode;
526 }
527
528 int
529 settings_get_fuzzbits (void)
530 {
531   return the_settings.fuzzbits;
532 }
533
534 void
535 settings_set_fuzzbits (int fuzzbits)
536 {
537   the_settings.fuzzbits = fuzzbits;
538 }
539
540 /* Return the current algorithm setting */
541 enum behavior_mode
542 settings_get_algorithm (void)
543 {
544   return the_settings.cmd_algorithm;
545 }
546
547 /* Set the algorithm option globally. */
548 void
549 settings_set_algorithm (enum behavior_mode mode)
550 {
551   the_settings.global_algorithm = the_settings.cmd_algorithm = mode;
552 }
553
554 /* Set the algorithm option for this command only */
555 void
556 settings_set_cmd_algorithm (enum behavior_mode mode)
557 {
558   the_settings.cmd_algorithm = mode;
559 }
560
561 /* Unset the algorithm option for this command */
562 void
563 unset_cmd_algorithm (void)
564 {
565   the_settings.cmd_algorithm = the_settings.global_algorithm;
566 }
567
568 /* Get the current syntax setting */
569 enum behavior_mode
570 settings_get_syntax (void)
571 {
572   return the_settings.syntax;
573 }
574
575 /* Set the syntax option */
576 void
577 settings_set_syntax (enum behavior_mode mode)
578 {
579   the_settings.syntax = mode;
580 }
581
582 \f
583 /* Sets custom currency specifier CC having name CC_NAME ('A' through
584    'E') to correspond to the settings in CC_STRING. */
585 bool
586 settings_set_cc (const char *cc_string, enum fmt_type type)
587 {
588   struct fmt_number_style *style = fmt_number_style_from_string (cc_string);
589   if (!style)
590     {
591       msg (SE, _("%s: Custom currency string `%s' does not contain "
592                  "exactly three periods or commas (or it contains both)."),
593            fmt_name (type), cc_string);
594       return false;
595     }
596
597   fmt_settings_set_cc (&the_settings.styles, type, style);
598   return true;
599 }
600
601 void
602 settings_set_decimal_char (char decimal)
603 {
604   the_settings.styles.decimal = decimal;
605 }
606
607 const struct fmt_settings *
608 settings_get_fmt_settings (void)
609 {
610   return &the_settings.styles;
611 }
612
613 double
614 settings_get_small (void)
615 {
616   return the_settings.small;
617 }
618
619 void
620 settings_set_small (double small)
621 {
622   the_settings.small = small;
623 }
624
625 /* Returns a string of the form "$#,###.##" according to FMT,
626    which must be of type FMT_DOLLAR.  The caller must free the
627    string. */
628 char *
629 settings_dollar_template (const struct fmt_spec *fmt)
630 {
631   struct string str = DS_EMPTY_INITIALIZER;
632   int c;
633   const struct fmt_number_style *fns ;
634
635   assert (fmt->type == FMT_DOLLAR);
636
637   fns = fmt_settings_get_style (&the_settings.styles, fmt->type);
638
639   ds_put_byte (&str, '$');
640   for (c = MAX (fmt->w - fmt->d - 1, 0); c > 0;)
641     {
642       ds_put_byte (&str, '#');
643       if (--c % 4 == 0 && c > 0)
644         {
645           ds_put_byte (&str, fns->grouping);
646           --c;
647         }
648     }
649   if (fmt->d > 0)
650     {
651       ds_put_byte (&str, fns->decimal);
652       ds_put_byte_multiple (&str, '#', fmt->d);
653     }
654
655   return ds_cstr (&str);
656 }
657
658 void
659 settings_set_output_routing (enum settings_output_type type,
660                              enum settings_output_devices devices)
661 {
662   assert (type < SETTINGS_N_OUTPUT_TYPES);
663   the_settings.output_routing[type] = devices;
664 }
665
666 enum settings_output_devices
667 settings_get_output_routing (enum settings_output_type type)
668 {
669   assert (type < SETTINGS_N_OUTPUT_TYPES);
670   return the_settings.output_routing[type] | SETTINGS_DEVICE_UNFILTERED;
671 }
672
673 enum settings_value_show
674 settings_get_show_values (void)
675 {
676   return the_settings.show_values;
677 }
678
679 void
680 settings_set_show_values (enum settings_value_show s)
681 {
682   the_settings.show_values = s;
683 }
684
685
686 enum settings_value_show
687 settings_get_show_variables (void)
688 {
689   return the_settings.show_variables;
690 }
691
692 void
693 settings_set_show_variables (enum settings_value_show s)
694 {
695   the_settings.show_variables = s;
696 }