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