4c0fde083740ea483852acbaa56e1b53b07dbbb8
[pspp] / src / data / settings.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011 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 #include <time.h>
24
25 #include "data/case.h"
26 #include "data/format.h"
27 #include "data/value.h"
28 #include "libpspp/i18n.h"
29 #include "libpspp/integer-format.h"
30 #include "libpspp/message.h"
31
32 #include "gl/minmax.h"
33 #include "gl/xalloc.h"
34
35 #include "gettext.h"
36 #define _(msgid) gettext (msgid)
37
38 struct settings
39 {
40   /* Integer format used for IB and PIB input. */
41   enum integer_format input_integer_format;
42
43   /* Floating-point format used for RB and RBHEX input. */
44   enum float_format input_float_format;
45
46   /* Format of integers in output (SET WIB). */
47   enum integer_format output_integer_format;
48
49   /* Format of reals in output (SET WRB). */
50   enum float_format output_float_format;
51
52   int viewlength;
53   int viewwidth;
54   bool safer_mode;
55   bool include;
56   int epoch;
57   bool route_errors_to_terminal;
58   bool route_errors_to_listing;
59   bool scompress;
60   bool undefined;
61   double blanks;
62   int max_messages[MSG_N_SEVERITIES];
63   bool printback;
64   bool mprint;
65   int mxloops;
66   size_t workspace;
67   struct fmt_spec default_format;
68   bool testing_mode;
69
70   int cmd_algorithm;
71   int global_algorithm;
72   int syntax;
73
74   struct fmt_settings *styles;
75
76   enum settings_output_devices output_routing[SETTINGS_N_OUTPUT_TYPES];
77
78   enum settings_var_style var_output_style;
79   enum settings_value_style value_output_style;
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   -1,                           /* epoch */
92   true,                         /* route_errors_to_terminal */
93   true,                         /* route_errors_to_listing */
94   true,                         /* scompress */
95   true,                         /* undefined */
96   SYSMIS,                       /* blanks */
97
98   /* max_messages */
99   {
100     100,                        /* MSG_S_ERROR */
101     100,                        /* MSG_S_WARNING */
102     100                         /* MSG_S_NOTE */
103   },
104
105   true,                         /* printback */
106   true,                         /* mprint */
107   40,                           /* mxloops */
108   64L * 1024 * 1024,            /* workspace */
109   {FMT_F, 8, 2},                /* default_format */
110   false,                        /* testing_mode */
111   ENHANCED,                     /* cmd_algorithm */
112   ENHANCED,                     /* global_algorithm */
113   ENHANCED,                     /* syntax */
114   NULL,                         /* styles */
115
116   /* output_routing */
117   {SETTINGS_DEVICE_LISTING | SETTINGS_DEVICE_TERMINAL,
118    SETTINGS_DEVICE_LISTING | SETTINGS_DEVICE_TERMINAL,
119    0,
120    SETTINGS_DEVICE_LISTING | SETTINGS_DEVICE_TERMINAL},
121
122   SETTINGS_VAR_STYLE_LABELS,
123   SETTINGS_VAL_STYLE_LABELS
124 };
125
126 /* Initializes the settings module. */
127 void
128 settings_init (void)
129 {
130   settings_set_epoch (-1);
131   the_settings.styles = fmt_settings_create ();
132
133   settings_set_decimal_char (get_system_decimal ());
134 }
135
136 /* Cleans up the settings module. */
137 void
138 settings_done (void)
139 {
140   settings_destroy (&the_settings);
141 }
142
143 static void
144 settings_copy (struct settings *dst, const struct settings *src)
145 {
146   *dst = *src;
147   dst->styles = fmt_settings_clone (src->styles);
148 }
149
150 /* Returns a copy of the current settings. */
151 struct settings *
152 settings_get (void)
153 {
154   struct settings *s = xmalloc (sizeof *s);
155   settings_copy (s, &the_settings);
156   return s;
157 }
158
159 /* Replaces the current settings by those in S.  The caller retains ownership
160    of S. */
161 void
162 settings_set (const struct settings *s)
163 {
164   settings_destroy (&the_settings);
165   settings_copy (&the_settings, s);
166 }
167
168 /* Destroys S. */
169 void
170 settings_destroy (struct settings *s)
171 {
172   if (s != NULL)
173     {
174       fmt_settings_destroy (s->styles);
175       if (s != &the_settings)
176         free (s);
177     }
178 }
179
180 /* Returns the floating-point format used for RB and RBHEX
181    input. */
182 enum float_format
183 settings_get_input_float_format (void)
184 {
185   return the_settings.input_float_format;
186 }
187
188 /* Sets the floating-point format used for RB and RBHEX input to
189    FORMAT. */
190 void
191 settings_set_input_float_format ( enum float_format format)
192 {
193   the_settings.input_float_format = format;
194 }
195
196 /* Returns the integer format used for IB and PIB input. */
197 enum integer_format
198 settings_get_input_integer_format (void)
199 {
200   return the_settings.input_integer_format;
201 }
202
203 /* Sets the integer format used for IB and PIB input to
204    FORMAT. */
205 void
206 settings_set_input_integer_format ( enum integer_format format)
207 {
208   the_settings.input_integer_format = format;
209 }
210
211 /* Returns the current output integer format. */
212 enum integer_format
213 settings_get_output_integer_format (void)
214 {
215   return the_settings.output_integer_format;
216 }
217
218 /* Sets the output integer format to INTEGER_FORMAT. */
219 void
220 settings_set_output_integer_format (
221                            enum integer_format integer_format)
222 {
223   the_settings.output_integer_format = integer_format;
224 }
225
226 /* Returns the current output float format. */
227 enum float_format
228 settings_get_output_float_format (void)
229 {
230   return the_settings.output_float_format;
231 }
232
233 /* Sets the output float format to FLOAT_FORMAT. */
234 void
235 settings_set_output_float_format ( enum float_format float_format)
236 {
237   the_settings.output_float_format = float_format;
238 }
239
240 /* Screen length in lines. */
241 int
242 settings_get_viewlength (void)
243 {
244   return the_settings.viewlength;
245 }
246
247 /* Sets the view length. */
248 void
249 settings_set_viewlength ( int viewlength_)
250 {
251   the_settings.viewlength = viewlength_;
252 }
253
254 /* Screen width. */
255 int
256 settings_get_viewwidth(void)
257 {
258   return the_settings.viewwidth;
259 }
260
261 /* Sets the screen width. */
262 void
263 settings_set_viewwidth ( int viewwidth_)
264 {
265   the_settings.viewwidth = viewwidth_;
266 }
267
268 /* Whether PSPP can erase and overwrite files. */
269 bool
270 settings_get_safer_mode (void)
271 {
272   return the_settings.safer_mode;
273 }
274
275 /* Set safer mode. */
276 void
277 settings_set_safer_mode (void)
278 {
279   the_settings.safer_mode = true;
280 }
281
282 /* If echo is on, whether commands from include files are echoed. */
283 bool
284 settings_get_include (void)
285 {
286   return the_settings.include;
287 }
288
289 /* Set include file echo. */
290 void
291 settings_set_include ( bool include)
292 {
293   the_settings.include = include;
294 }
295
296 /* What year to use as the start of the epoch. */
297 int
298 settings_get_epoch (void)
299 {
300   assert (the_settings.epoch >= 0);
301
302   return the_settings.epoch;
303 }
304
305 /* Sets the year that starts the epoch. */
306 void
307 settings_set_epoch ( int epoch)
308 {
309   if (epoch < 0)
310     {
311       time_t t = time (0);
312       struct tm *tm = localtime (&t);
313       epoch = (tm != NULL ? tm->tm_year + 1900 : 2000) - 69;
314     }
315
316   the_settings.epoch = epoch;
317   assert (the_settings.epoch >= 0);
318 }
319
320 /* Compress system files by default? */
321 bool
322 settings_get_scompression (void)
323 {
324   return the_settings.scompress;
325 }
326
327 /* Set system file default compression. */
328 void
329 settings_set_scompression ( bool scompress)
330 {
331   the_settings.scompress = scompress;
332 }
333
334 /* Whether to warn on undefined values in numeric data. */
335 bool
336 settings_get_undefined (void)
337 {
338   return the_settings.undefined;
339 }
340
341 /* Set whether to warn on undefined values. */
342 void
343 settings_set_undefined ( bool undefined)
344 {
345   the_settings.undefined = undefined;
346 }
347
348 /* The value that blank numeric fields are set to when read in. */
349 double
350 settings_get_blanks (void)
351 {
352   return the_settings.blanks;
353 }
354
355 /* Set the value that blank numeric fields are set to when read
356    in. */
357 void
358 settings_set_blanks ( double blanks)
359 {
360   the_settings.blanks = blanks;
361 }
362
363 /* Returns the maximum number of messages to show of the given SEVERITY before
364    aborting.  (The value for MSG_S_WARNING is interpreted as maximum number of
365    warnings and errors combined.) */
366 int
367 settings_get_max_messages (enum msg_severity severity)
368 {
369   assert (severity < MSG_N_SEVERITIES);
370   return the_settings.max_messages[severity];
371 }
372
373 /* Sets the maximum number of messages to show of the given SEVERITY before
374    aborting to MAX.  (The value for MSG_S_WARNING is interpreted as maximum
375    number of warnings and errors combined.)  In addition, in the case of 
376    warnings the special value of zero indicates that no warnings are to be
377    issued. 
378 */
379 void
380 settings_set_max_messages (enum msg_severity severity, int max)
381 {
382   assert (severity < MSG_N_SEVERITIES);
383
384   if (severity == MSG_S_WARNING)
385     {
386       if ( max == 0)
387         {
388           msg (MW,
389                _("MXWARNS set to zero.  No further warnings will be given even when potentially problematic situations are encountered."));
390           msg_ui_disable_warnings (true);
391         }
392       else if ( the_settings.max_messages [MSG_S_WARNING] == 0)
393         {
394           msg_ui_disable_warnings (false);
395           the_settings.max_messages[MSG_S_WARNING] = max;
396           msg (MW, _("Warnings re-enabled. %d warnings will be issued before aborting syntax processing."), max);
397         }
398     }
399
400   the_settings.max_messages[severity] = max;
401 }
402
403 /* Independent of get_printback, controls whether the commands
404    generated by macro invocations are displayed. */
405 bool
406 settings_get_mprint (void)
407 {
408   return the_settings.mprint;
409 }
410
411 /* Sets whether the commands generated by macro invocations are
412    displayed. */
413 void
414 settings_set_mprint ( bool mprint)
415 {
416   the_settings.mprint = mprint;
417 }
418
419 /* Implied limit of unbounded loop. */
420 int
421 settings_get_mxloops (void)
422 {
423   return the_settings.mxloops;
424 }
425
426 /* Set implied limit of unbounded loop. */
427 void
428 settings_set_mxloops ( int mxloops)
429 {
430   the_settings.mxloops = mxloops;
431 }
432
433 /* Approximate maximum amount of memory to use for cases, in
434    bytes. */
435 size_t
436 settings_get_workspace (void)
437 {
438   return the_settings.workspace;
439 }
440
441 /* Approximate maximum number of cases to allocate in-core, given
442    that each case has the format given in PROTO. */
443 size_t
444 settings_get_workspace_cases (const struct caseproto *proto)
445 {
446   size_t n_cases = settings_get_workspace () / case_get_cost (proto);
447   return MAX (n_cases, 4);
448 }
449
450 /* Set approximate maximum amount of memory to use for cases, in
451    bytes. */
452
453 void
454 settings_set_workspace (size_t workspace)
455 {
456   the_settings.workspace = workspace;
457 }
458
459 /* Default format for variables created by transformations and by
460    DATA LIST {FREE,LIST}. */
461 const struct fmt_spec *
462 settings_get_format (void)
463 {
464   return &the_settings.default_format;
465 }
466
467 /* Set default format for variables created by transformations
468    and by DATA LIST {FREE,LIST}. */
469 void
470 settings_set_format ( const struct fmt_spec *default_format)
471 {
472   the_settings.default_format = *default_format;
473 }
474
475 /* Are we in testing mode?  (e.g. --testing-mode command line
476    option) */
477 bool
478 settings_get_testing_mode (void)
479 {
480   return the_settings.testing_mode;
481 }
482
483 /* Set testing mode. */
484 void
485 settings_set_testing_mode ( bool testing_mode)
486 {
487   the_settings.testing_mode = testing_mode;
488 }
489
490 /* Return the current algorithm setting */
491 enum behavior_mode
492 settings_get_algorithm (void)
493 {
494   return the_settings.cmd_algorithm;
495 }
496
497 /* Set the algorithm option globally. */
498 void
499 settings_set_algorithm (enum behavior_mode mode)
500 {
501   the_settings.global_algorithm = the_settings.cmd_algorithm = mode;
502 }
503
504 /* Set the algorithm option for this command only */
505 void
506 settings_set_cmd_algorithm ( enum behavior_mode mode)
507 {
508   the_settings.cmd_algorithm = mode;
509 }
510
511 /* Unset the algorithm option for this command */
512 void
513 unset_cmd_algorithm (void)
514 {
515   the_settings.cmd_algorithm = the_settings.global_algorithm;
516 }
517
518 /* Get the current syntax setting */
519 enum behavior_mode
520 settings_get_syntax (void)
521 {
522   return the_settings.syntax;
523 }
524
525 /* Set the syntax option */
526 void
527 settings_set_syntax ( enum behavior_mode mode)
528 {
529   the_settings.syntax = mode;
530 }
531
532 \f
533
534 /* Find the grouping characters in CC_STRING and sets *GROUPING and *DECIMAL
535    appropriately.  Returns true if successful, false otherwise. */
536 static bool
537 find_cc_separators (const char *cc_string, char *decimal, char *grouping)
538 {
539   const char *sp;
540   int comma_cnt, dot_cnt;
541
542   /* Count commas and periods.  There must be exactly three of
543      one or the other, except that an apostrophe escapes a
544      following comma or period. */
545   comma_cnt = dot_cnt = 0;
546   for (sp = cc_string; *sp; sp++)
547     if (*sp == ',')
548       comma_cnt++;
549     else if (*sp == '.')
550       dot_cnt++;
551     else if (*sp == '\'' && (sp[1] == '.' || sp[1] == ',' || sp[1] == '\''))
552       sp++;
553
554   if ((comma_cnt == 3) == (dot_cnt == 3))
555     return false;
556
557   if (comma_cnt == 3)
558     {
559       *decimal = '.';
560       *grouping = ',';
561     }
562   else
563     {
564       *decimal = ',';
565       *grouping = '.';
566     }
567   return true;
568 }
569
570 /* Extracts a token from IN into a newly allocated string AFFIXP.  Tokens are
571    delimited by GROUPING.  Returns the first character following the token. */
572 static const char *
573 extract_cc_token (const char *in, int grouping, char **affixp)
574 {
575   char *out;
576
577   out = *affixp = xmalloc (strlen (in) + 1);
578   for (; *in != '\0' && *in != grouping; in++)
579     {
580       if (*in == '\'' && in[1] == grouping)
581         in++;
582       *out++ = *in;
583     }
584   *out = '\0';
585
586   if (*in == grouping)
587     in++;
588   return in;
589 }
590
591 /* Sets custom currency specifier CC having name CC_NAME ('A' through
592    'E') to correspond to the settings in CC_STRING. */
593 bool
594 settings_set_cc (const char *cc_string, enum fmt_type type)
595 {
596   char *neg_prefix, *prefix, *suffix, *neg_suffix;
597   char decimal, grouping;
598
599   assert (fmt_get_category (type) == FMT_CAT_CUSTOM);
600
601   /* Determine separators. */
602   if (!find_cc_separators (cc_string, &decimal, &grouping))
603     {
604       msg (SE, _("%s: Custom currency string `%s' does not contain "
605                  "exactly three periods or commas (or it contains both)."),
606            fmt_name (type), cc_string);
607       return false;
608     }
609
610   cc_string = extract_cc_token (cc_string, grouping, &neg_prefix);
611   cc_string = extract_cc_token (cc_string, grouping, &prefix);
612   cc_string = extract_cc_token (cc_string, grouping, &suffix);
613   cc_string = extract_cc_token (cc_string, grouping, &neg_suffix);
614
615   fmt_settings_set_style (the_settings.styles, type, decimal, grouping,
616                           neg_prefix, prefix, suffix, neg_suffix);
617
618   free (neg_suffix);
619   free (suffix);
620   free (prefix);
621   free (neg_prefix);
622
623   return true;
624 }
625
626 /* Returns the decimal point character for TYPE. */
627 int
628 settings_get_decimal_char (enum fmt_type type)
629 {
630   return fmt_settings_get_style (the_settings.styles, type)->decimal;
631 }
632
633 void
634 settings_set_decimal_char (char decimal)
635 {
636   fmt_settings_set_decimal (the_settings.styles, decimal);
637 }
638
639 /* Returns the number formatting style associated with the given
640    format TYPE. */
641 const struct fmt_number_style *
642 settings_get_style (enum fmt_type type)
643 {
644   assert (is_fmt_type (type));
645   return fmt_settings_get_style (the_settings.styles, type);
646 }
647
648 /* Returns a string of the form "$#,###.##" according to FMT,
649    which must be of type FMT_DOLLAR.  The caller must free the
650    string. */
651 char *
652 settings_dollar_template (const struct fmt_spec *fmt)
653 {
654   struct string str = DS_EMPTY_INITIALIZER;
655   int c;
656   const struct fmt_number_style *fns ;
657
658   assert (fmt->type == FMT_DOLLAR);
659
660   fns = fmt_settings_get_style (the_settings.styles, fmt->type);
661
662   ds_put_byte (&str, '$');
663   for (c = MAX (fmt->w - fmt->d - 1, 0); c > 0; )
664     {
665       ds_put_byte (&str, '#');
666       if (--c % 4 == 0 && c > 0)
667         {
668           ds_put_byte (&str, fns->grouping);
669           --c;
670         }
671     }
672   if (fmt->d > 0)
673     {
674       ds_put_byte (&str, fns->decimal);
675       ds_put_byte_multiple (&str, '#', fmt->d);
676     }
677
678   return ds_cstr (&str);
679 }
680
681 void
682 settings_set_output_routing (enum settings_output_type type,
683                              enum settings_output_devices devices)
684 {
685   assert (type < SETTINGS_N_OUTPUT_TYPES);
686   the_settings.output_routing[type] = devices;
687 }
688
689 enum settings_output_devices
690 settings_get_output_routing (enum settings_output_type type)
691 {
692   assert (type < SETTINGS_N_OUTPUT_TYPES);
693   return the_settings.output_routing[type] | SETTINGS_DEVICE_UNFILTERED;
694 }
695
696 enum settings_value_style 
697 settings_get_value_style (void)
698 {
699   return the_settings.value_output_style;
700 }
701
702 void
703 settings_set_value_style (enum settings_value_style s)
704 {
705   the_settings.value_output_style = s;
706 }
707
708
709
710 enum settings_var_style
711 settings_get_var_style (void)
712 {
713   return the_settings.var_output_style;
714 }
715
716
717 void
718 settings_set_var_style (enum settings_var_style s)
719 {
720   the_settings.var_output_style = s;
721 }