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