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