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