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