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