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