1#!/usr/bin/perl -w 2 3# settings.pl: generate settings.c from settings.dat 4# Copyright (c) 2002-2018 Philip Kendall, BogDan Vatra, Alistair Cree 5 6# This program is free software; you can redistribute it and/or modify 7# it under the terms of the GNU General Public License as published by 8# the Free Software Foundation; either version 2 of the License, or 9# (at your option) any later version. 10 11# This program is distributed in the hope that it will be useful, 12# but WITHOUT ANY WARRANTY; without even the implied warranty of 13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14# GNU General Public License for more details. 15 16# You should have received a copy of the GNU General Public License along 17# with this program; if not, write to the Free Software Foundation, Inc., 18# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 20# Author contact information: 21 22# E-mail: philip-fuse@shadowmagic.org.uk 23 24use strict; 25 26use Fuse; 27 28sub hashline ($) { '#line ', $_[0] + 1, '"', __FILE__, "\"\n" } 29 30my %options; 31 32while(<>) { 33 34 next if /^\s*$/; 35 next if /^\s*#/; 36 37 chomp; 38 39 my( $name, $type, $default, $short, $commandline, $configfile ) = 40 split /\s*,\s*/; 41 42 if( ( not defined $commandline ) || ( $commandline eq '' ) ) { 43 $commandline = $name; 44 $commandline =~ s/_/-/g; 45 } 46 47 if( ( not defined $configfile ) || ( $configfile eq '' ) ) { 48 $configfile = $commandline; 49 $configfile =~ s/-//g; 50 } 51 52 $options{$name} = { type => $type, default => $default, short => $short, 53 commandline => $commandline, 54 configfile => $configfile }; 55} 56 57print Fuse::GPL( 'settings.c: Handling configuration settings', 58 '2002 Philip Kendall' ); 59 60print hashline( __LINE__ ), << 'CODE'; 61 62/* This file is autogenerated from settings.dat by settings.pl. 63 Do not edit unless you know what will happen! */ 64 65#include <config.h> 66 67#include <errno.h> 68#include <stdio.h> 69#include <stdlib.h> 70#include <string.h> 71#include <sys/types.h> 72#include <sys/stat.h> 73#include <unistd.h> 74 75#ifdef HAVE_GETOPT_LONG /* Did our libc include getopt_long? */ 76#include <getopt.h> 77#elif defined AMIGA || defined __MORPHOS__ /* #ifdef HAVE_GETOPT_LONG */ 78/* The platform uses GNU getopt, but not getopt_long, so we get 79 symbol clashes on this platform. Just use getopt */ 80#else /* #ifdef HAVE_GETOPT_LONG */ 81#include "compat.h" /* If not, use ours */ 82#endif /* #ifdef HAVE_GETOPT_LONG */ 83 84#ifdef HAVE_LIB_XML2 85#include <libxml/xmlmemory.h> 86#include <libxml/parser.h> 87#endif /* #ifdef HAVE_LIB_XML2 */ 88 89#include "fuse.h" 90#include "infrastructure/startup_manager.h" 91#include "machine.h" 92#include "settings.h" 93#include "spectrum.h" 94#include "ui/ui.h" 95#include "utils.h" 96 97/* The name of our configuration file */ 98#ifdef WIN32 99#define CONFIG_FILE_NAME "fuse.cfg" 100#else /* #ifdef WIN32 */ 101#define CONFIG_FILE_NAME ".fuserc" 102#endif /* #ifdef WIN32 */ 103 104/* The current settings of options, etc */ 105settings_info settings_current; 106 107/* The default settings of options, etc */ 108settings_info settings_default = { 109CODE 110 111 foreach my $name ( sort keys %options ) { 112 next if $options{$name}->{type} eq 'null'; 113 if( $options{$name}->{type} eq 'string' ) { 114 print " /* $name */ (char *)$options{$name}->{default},\n"; 115 } else { 116 print " /* $name */ $options{$name}->{default},\n"; 117 } 118 } 119 120print hashline( __LINE__ ), << 'CODE'; 121 /* show_help */ 0, 122 /* show_version */ 0, 123}; 124 125static int read_config_file( settings_info *settings ); 126 127#ifdef HAVE_LIB_XML2 128static int parse_xml( xmlDocPtr doc, settings_info *settings ); 129#else /* #ifdef HAVE_LIB_XML2 */ 130static int parse_ini( utils_file *file, settings_info *settings ); 131#endif /* #ifdef HAVE_LIB_XML2 */ 132 133static int settings_command_line( settings_info *settings, int *first_arg, 134 int argc, char **argv ); 135 136static void settings_copy_internal( settings_info *dest, settings_info *src ); 137 138/* Called on emulator startup */ 139int 140settings_init( int *first_arg, int argc, char **argv ) 141{ 142 int error; 143 144 settings_defaults( &settings_current ); 145 146 error = read_config_file( &settings_current ); 147 if( error ) return error; 148 149 error = settings_command_line( &settings_current, first_arg, argc, argv ); 150 if( error ) return error; 151 152 return 0; 153} 154 155/* Fill the settings structure with sensible defaults */ 156void settings_defaults( settings_info *settings ) 157{ 158 settings_copy_internal( settings, &settings_default ); 159} 160 161#ifdef HAVE_LIB_XML2 162 163/* Read options from the config file (if libxml2 is available) */ 164 165static int 166read_config_file( settings_info *settings ) 167{ 168 const char *cfgdir; char path[ PATH_MAX ]; 169 170 xmlDocPtr doc; 171 172 cfgdir = compat_get_config_path(); if( !cfgdir ) return 1; 173 174 snprintf( path, PATH_MAX, "%s/%s", cfgdir, CONFIG_FILE_NAME ); 175 176 /* See if the file exists; if doesn't, it's not a problem */ 177 if( !compat_file_exists( path ) ) { 178 return 0; 179 } 180 181 doc = xmlReadFile( path, NULL, 0 ); 182 if( !doc ) { 183 ui_error( UI_ERROR_ERROR, "error reading config file" ); 184 return 1; 185 } 186 187 if( parse_xml( doc, settings ) ) { 188 xmlFreeDoc( doc ); 189 return 1; 190 } 191 192 xmlFreeDoc( doc ); 193 194 return 0; 195} 196 197static int 198parse_xml( xmlDocPtr doc, settings_info *settings ) 199{ 200 xmlNodePtr node; 201 xmlChar *xmlstring; 202 203 node = xmlDocGetRootElement( doc ); 204 if( xmlStrcmp( node->name, (const xmlChar*)"settings" ) ) { 205 ui_error( UI_ERROR_ERROR, "config file's root node is not 'settings'" ); 206 return 1; 207 } 208 209 node = node->xmlChildrenNode; 210 while( node ) { 211 212CODE 213 214foreach my $name ( sort keys %options ) { 215 216 my $type = $options{$name}->{type}; 217 218 if( $type eq 'boolean' or $type eq 'numeric' ) { 219 220 print << "CODE"; 221 if( !strcmp( (const char*)node->name, "$options{$name}->{configfile}" ) ) { 222 xmlstring = xmlNodeListGetString( doc, node->xmlChildrenNode, 1 ); 223 if( xmlstring ) { 224 settings->$name = atoi( (char*)xmlstring ); 225 xmlFree( xmlstring ); 226 } 227 } else 228CODE 229 230 } elsif( $type eq 'string' ) { 231 232 print << "CODE"; 233 if( !strcmp( (const char*)node->name, "$options{$name}->{configfile}" ) ) { 234 xmlstring = xmlNodeListGetString( doc, node->xmlChildrenNode, 1 ); 235 if( xmlstring ) { 236 libspectrum_free( settings->$name ); 237 settings->$name = utils_safe_strdup( (char*)xmlstring ); 238 xmlFree( xmlstring ); 239 } 240 } else 241CODE 242 243 } elsif( $type eq 'null' ) { 244 245 print << "CODE"; 246 if( !strcmp( (const char*)node->name, "$options{$name}->{configfile}" ) ) { 247 /* Do nothing */ 248 } else 249CODE 250 251 } else { 252 die "Unknown setting type `$type'"; 253 } 254} 255 256print hashline( __LINE__ ), << 'CODE'; 257 if( !strcmp( (const char*)node->name, "text" ) ) { 258 /* Do nothing */ 259 } else { 260 ui_error( UI_ERROR_WARNING, "Unknown setting '%s' in config file", 261 node->name ); 262 } 263 264 node = node->next; 265 } 266 267 return 0; 268} 269 270int 271settings_write_config( settings_info *settings ) 272{ 273 const char *cfgdir; char path[ PATH_MAX ], buffer[80]; 274 275 xmlDocPtr doc; xmlNodePtr root; 276 277 cfgdir = compat_get_config_path(); if( !cfgdir ) return 1; 278 279 snprintf( path, PATH_MAX, "%s/%s", cfgdir, CONFIG_FILE_NAME ); 280 281 /* Create the XML document */ 282 doc = xmlNewDoc( (const xmlChar*)"1.0" ); 283 284 root = xmlNewNode( NULL, (const xmlChar*)"settings" ); 285 xmlDocSetRootElement( doc, root ); 286CODE 287 288foreach my $name ( sort keys %options ) { 289 290 my $type = $options{$name}->{type}; 291 292 if( $type eq 'boolean' ) { 293 294 print " xmlNewTextChild( root, NULL, (const xmlChar*)\"$options{$name}->{configfile}\", (const xmlChar*)(settings->$name ? \"1\" : \"0\") );\n"; 295 296 } elsif( $type eq 'string' ) { 297 print << "CODE"; 298 if( settings->$name ) 299 xmlNewTextChild( root, NULL, (const xmlChar*)"$options{$name}->{configfile}", (const xmlChar*)settings->$name ); 300CODE 301 } elsif( $type eq 'numeric' ) { 302 print << "CODE"; 303 snprintf( buffer, 80, "%d", settings->$name ); 304 xmlNewTextChild( root, NULL, (const xmlChar*)"$options{$name}->{configfile}", (const xmlChar*)buffer ); 305CODE 306 } elsif( $type eq 'null' ) { 307 # Do nothing 308 } else { 309 die "Unknown setting type `$type'"; 310 } 311} 312 313 print hashline( __LINE__ ), << 'CODE'; 314 315 xmlSaveFormatFile( path, doc, 1 ); 316 317 xmlFreeDoc( doc ); 318 319 return 0; 320} 321 322#else /* #ifdef HAVE_LIB_XML2 */ 323 324/* Read options from the config file as ini file (if libxml2 is not available) */ 325 326static int 327read_config_file( settings_info *settings ) 328{ 329 const char *cfgdir; char path[ PATH_MAX ]; 330 struct stat stat_info; 331 int error; 332 333 utils_file file; 334 335 cfgdir = compat_get_config_path(); if( !cfgdir ) return 1; 336 337 snprintf( path, PATH_MAX, "%s/%s", cfgdir, CONFIG_FILE_NAME ); 338 339 /* See if the file exists; if doesn't, it's not a problem */ 340 if( stat( path, &stat_info ) ) { 341 if( errno == ENOENT ) { 342 return 0; 343 } else { 344 ui_error( UI_ERROR_ERROR, "couldn't stat '%s': %s", path, 345 strerror( errno ) ); 346 return 1; 347 } 348 } 349 350 error = utils_read_file( path, &file ); 351 if( error ) { 352 ui_error( UI_ERROR_ERROR, "error reading config file" ); 353 return 1; 354 } 355 356 if( parse_ini( &file, settings ) ) { utils_close_file( &file ); return 1; } 357 358 utils_close_file( &file ); 359 360 return 0; 361} 362 363static int 364settings_var( settings_info *settings, unsigned char *name, unsigned char *last, 365 int **val_int, char ***val_char, unsigned char **next ) 366{ 367 unsigned char* cpos; 368 size_t n; 369 370 *val_int = NULL; 371 *val_char = NULL; 372 373 *next = name; 374 while( name < last && ( *name == ' ' || *name == '\t' || *name == '\r' || 375 *name == '\n' ) ) { 376 *next = ++name; /* seek to first char */ 377 } 378 cpos = name; 379 380 while( cpos < last && ( *cpos != '=' && *cpos != ' ' && *cpos != '\t' && 381 *cpos != '\r' && *cpos != '\n' ) ) cpos++; 382 *next = cpos; 383 n = cpos - name; /* length of name */ 384 385 while( *next < last && **next != '=' ) { /* search for '=' */ 386 if( **next != ' ' && **next != '\t' && **next != '\r' && **next != '\n' ) 387 return 1; /* error in value */ 388 (*next)++; 389 } 390 if( *next < last) (*next)++; /* set after '=' */ 391/* ui_error( UI_ERROR_WARNING, "Config: (%5s): ", name ); */ 392 393CODE 394my %type = ('null' => 0, 'boolean' => 1, 'numeric' => 1, 'string' => 2 ); 395foreach my $name ( sort keys %options ) { 396 my $len = length $options{$name}->{configfile}; 397 398 print << "CODE"; 399 if( n == $len && !strncmp( (const char *)name, "$options{$name}->{configfile}", n ) ) { 400CODE 401 print " *val_int = \&settings->$name;\n" if( $options{$name}->{type} eq 'boolean' or $options{$name}->{type} eq 'numeric' ); 402 print " *val_char = \&settings->$name;\n" if( $options{$name}->{type} eq 'string' ); 403 print "/* *val_null = \&settings->$name; */\n" if( $options{$name}->{type} eq 'null' ); 404 print << "CODE"; 405 return 0; 406 } 407CODE 408} 409 print << "CODE"; 410 return 1; 411} 412 413static int 414parse_ini( utils_file *file, settings_info *settings ) 415{ 416 unsigned char *cpos, *cpos_new; 417 int *val_int; 418 char **val_char; 419 420 cpos = file->buffer; 421 422 /* Read until the end of file */ 423 while( cpos < file->buffer + file->length ) { 424 if( settings_var( settings, cpos, file->buffer + file->length, &val_int, 425 &val_char, &cpos_new ) ) { 426 /* error in name or something else ... */ 427 cpos = cpos_new + 1; 428 ui_error( UI_ERROR_WARNING, 429 "Unknown and/or invalid setting '%s' in config file", cpos ); 430 continue; 431 } 432 cpos = cpos_new; 433 if( val_int ) { 434 *val_int = atoi( (char *)cpos ); 435 while( cpos < file->buffer + file->length && 436 ( *cpos != '\\0' && *cpos != '\\r' && *cpos != '\\n' ) ) cpos++; 437 } else if( val_char ) { 438 char *value = (char *)cpos; 439 size_t n = 0; 440 while( cpos < file->buffer + file->length && 441 ( *cpos != '\\0' && *cpos != '\\r' && *cpos != '\\n' ) ) cpos++; 442 n = (char *)cpos - value; 443 if( n > 0 ) { 444 if( *val_char != NULL ) { 445 libspectrum_free( *val_char ); 446 *val_char = NULL; 447 } 448 *val_char = libspectrum_new( char, n + 1 ); 449 (*val_char)[n] = '\\0'; 450 memcpy( *val_char, value, n ); 451 } 452 } 453 /* skip 'new line' like chars */ 454 while( ( cpos < ( file->buffer + file->length ) ) && 455 ( *cpos == '\\r' || *cpos == '\\n' ) ) cpos++; 456 457CODE 458print hashline( __LINE__ ), << 'CODE'; 459 } 460 461 return 0; 462} 463 464static int 465settings_file_write( compat_fd fd, const char *buffer, size_t length ) 466{ 467 return compat_file_write( fd, (const unsigned char *)buffer, length ); 468} 469 470static int 471settings_string_write( compat_fd doc, const char* name, const char* config ) 472{ 473 if( config != NULL && 474 ( settings_file_write( doc, name, strlen( name ) ) || 475 settings_file_write( doc, "=", 1 ) || 476 settings_file_write( doc, config, strlen( config ) ) || 477 settings_file_write( doc, FUSE_EOL, strlen( FUSE_EOL ) ) ) ) 478 return 1; 479 return 0; 480} 481 482static int 483settings_boolean_write( compat_fd doc, const char* name, int config ) 484{ 485 return settings_string_write( doc, name, config ? "1" : "0" ); 486} 487 488static int 489settings_numeric_write( compat_fd doc, const char* name, int config ) 490{ 491 char buffer[80]; 492 snprintf( buffer, sizeof( buffer ), "%d", config ); 493 return settings_string_write( doc, name, buffer ); 494} 495 496int 497settings_write_config( settings_info *settings ) 498{ 499 const char *cfgdir; char path[ PATH_MAX ]; 500 501 compat_fd doc; 502 503 cfgdir = compat_get_config_path(); if( !cfgdir ) return 1; 504 505 snprintf( path, PATH_MAX, "%s/%s", cfgdir, CONFIG_FILE_NAME ); 506 507 doc = compat_file_open( path, 1 ); 508 if( doc == COMPAT_FILE_OPEN_FAILED ) { 509 ui_error( UI_ERROR_ERROR, "couldn't open `%s' for writing: %s\n", 510 path, strerror( errno ) ); 511 return 1; 512 } 513 514CODE 515 516foreach my $name ( sort keys %options ) { 517 518 my $type = $options{$name}->{type}; 519 my $len = length "$options{$name}->{configfile}"; 520 521 if( $type eq 'boolean' ) { 522 523 print << "CODE"; 524 if( settings_boolean_write( doc, "$options{$name}->{configfile}", 525 settings->$name ) ) 526 goto error; 527CODE 528 529 } elsif( $type eq 'string' ) { 530 print << "CODE"; 531 if( settings_string_write( doc, "$options{$name}->{configfile}", 532 settings->$name ) ) 533 goto error; 534CODE 535 536 } elsif( $type eq 'numeric' ) { 537 print << "CODE"; 538 if( settings_numeric_write( doc, "$options{$name}->{configfile}", 539 settings->$name ) ) 540 goto error; 541CODE 542 543 } elsif( $type eq 'null' ) { 544 # Do nothing 545 } else { 546 die "Unknown setting type `$type'"; 547 } 548} 549 550 print hashline( __LINE__ ), << 'CODE'; 551 552 compat_file_close( doc ); 553 554 return 0; 555error: 556 compat_file_close( doc ); 557 558 return 1; 559} 560 561#endif /* #ifdef HAVE_LIB_XML2 */ 562 563/* Read options from the command line */ 564static int 565settings_command_line( settings_info *settings, int *first_arg, 566 int argc, char **argv ) 567{ 568#ifdef GEKKO 569 /* No argv on the Wii. Just return */ 570 return 0; 571#endif 572 573#if !defined AMIGA && !defined __MORPHOS__ 574 575 struct option long_options[] = { 576 577CODE 578 579my $fake_short_option = 256; 580 581foreach my $name ( sort keys %options ) { 582 583 my $type = $options{$name}->{type}; 584 my $commandline = $options{$name}->{commandline}; 585 my $short = $options{$name}->{short}; 586 587 unless( $type eq 'boolean' or $short ) { $short = $fake_short_option++ } 588 589 if( $type eq 'boolean' ) { 590 591 print << "CODE"; 592 { "$commandline", 0, &(settings->$name), 1 }, 593 { "no-$commandline", 0, &(settings->$name), 0 }, 594CODE 595 } elsif( $type eq 'string' or $type eq 'numeric' ) { 596 597 print " { \"$commandline\", 1, NULL, $short },\n"; 598 } elsif( $type eq 'null' ) { 599 # Do nothing 600 } else { 601 die "Unknown setting type `$type'"; 602 } 603} 604 605print hashline( __LINE__ ), << 'CODE'; 606 607 { "help", 0, NULL, 'h' }, 608 { "version", 0, NULL, 'V' }, 609 610 { 0, 0, 0, 0 } /* End marker: DO NOT REMOVE */ 611 }; 612 613#endif /* #ifndef AMIGA */ 614 615 while( 1 ) { 616 617 int c; 618 619#if defined AMIGA || defined __MORPHOS__ 620 c = getopt( argc, argv, "d:hm:o:p:f:r:s:t:v:g:j:V" ); 621#else /* #ifdef AMIGA */ 622 c = getopt_long( argc, argv, "d:hm:o:p:f:r:s:t:v:g:j:V", long_options, NULL ); 623#endif /* #ifdef AMIGA */ 624 625 if( c == -1 ) break; /* End of option list */ 626 627 switch( c ) { 628 629 case 0: break; /* Used for long option returns */ 630 631CODE 632 633$fake_short_option = 256; 634 635foreach my $name ( sort keys %options ) { 636 637 my $type = $options{$name}->{type}; 638 my $short = $options{$name}->{short}; 639 640 unless( $type eq 'boolean' or $short ) { $short = $fake_short_option++ } 641 642 if( $type eq 'boolean' ) { 643 # Do nothing 644 } elsif( $type eq 'string' ) { 645 print " case $short: settings_set_string( &settings->$name, optarg ); break;\n"; 646 } elsif( $type eq 'numeric' ) { 647 print " case $short: settings->$name = atoi( optarg ); break;\n"; 648 } elsif( $type eq 'null' ) { 649 # Do nothing 650 } else { 651 die "Unknown setting type `$type'"; 652 } 653} 654 655print hashline( __LINE__ ), << 'CODE'; 656 657 case 'h': settings->show_help = 1; break; 658 case 'V': settings->show_version = 1; break; 659 660 case ':': 661 case '?': 662 break; 663 664 default: 665 fprintf( stderr, "%s: getopt_long returned `%c'\n", 666 fuse_progname, (char)c ); 667 break; 668 669 } 670 } 671 672 /* Store the location of the first non-option argument */ 673 *first_arg = optind; 674 675 return 0; 676} 677 678/* Copy one settings object to another */ 679static void 680settings_copy_internal( settings_info *dest, settings_info *src ) 681{ 682 settings_free( dest ); 683 684CODE 685 686foreach my $name ( sort keys %options ) { 687 688 my $type = $options{$name}->{type}; 689 690 if( $type eq 'boolean' or $type eq 'numeric' ) { 691 print " dest->$name = src->$name;\n"; 692 } elsif( $type eq 'string' ) { 693 print << "CODE"; 694 dest->$name = NULL; 695 if( src->$name ) { 696 dest->$name = utils_safe_strdup( src->$name ); 697 } 698CODE 699 } 700} 701 702print hashline( __LINE__ ), << 'CODE'; 703} 704 705/* Copy one settings object to another */ 706void settings_copy( settings_info *dest, settings_info *src ) 707{ 708 settings_defaults( dest ); 709 settings_copy_internal( dest, src ); 710} 711 712char ** 713settings_get_rom_setting( settings_info *settings, size_t which, 714 int is_peripheral ) 715{ 716 if( !is_peripheral ) { 717 switch( which ) { 718 case 0: return &( settings->rom_16 ); 719 case 1: return &( settings->rom_48 ); 720 case 2: return &( settings->rom_128_0 ); 721 case 3: return &( settings->rom_128_1 ); 722 case 4: return &( settings->rom_plus2_0 ); 723 case 5: return &( settings->rom_plus2_1 ); 724 case 6: return &( settings->rom_plus2a_0 ); 725 case 7: return &( settings->rom_plus2a_1 ); 726 case 8: return &( settings->rom_plus2a_2 ); 727 case 9: return &( settings->rom_plus2a_3 ); 728 case 10: return &( settings->rom_plus3_0 ); 729 case 11: return &( settings->rom_plus3_1 ); 730 case 12: return &( settings->rom_plus3_2 ); 731 case 13: return &( settings->rom_plus3_3 ); 732 case 14: return &( settings->rom_plus3e_0 ); 733 case 15: return &( settings->rom_plus3e_1 ); 734 case 16: return &( settings->rom_plus3e_2 ); 735 case 17: return &( settings->rom_plus3e_3 ); 736 case 18: return &( settings->rom_tc2048 ); 737 case 19: return &( settings->rom_tc2068_0 ); 738 case 20: return &( settings->rom_tc2068_1 ); 739 case 21: return &( settings->rom_ts2068_0 ); 740 case 22: return &( settings->rom_ts2068_1 ); 741 case 23: return &( settings->rom_pentagon_0 ); 742 case 24: return &( settings->rom_pentagon_1 ); 743 case 25: return &( settings->rom_pentagon_2 ); 744 case 26: return &( settings->rom_pentagon512_0 ); 745 case 27: return &( settings->rom_pentagon512_1 ); 746 case 28: return &( settings->rom_pentagon512_2 ); 747 case 29: return &( settings->rom_pentagon512_3 ); 748 case 30: return &( settings->rom_pentagon1024_0 ); 749 case 31: return &( settings->rom_pentagon1024_1 ); 750 case 32: return &( settings->rom_pentagon1024_2 ); 751 case 33: return &( settings->rom_pentagon1024_3 ); 752 case 34: return &( settings->rom_scorpion_0 ); 753 case 35: return &( settings->rom_scorpion_1 ); 754 case 36: return &( settings->rom_scorpion_2 ); 755 case 37: return &( settings->rom_scorpion_3 ); 756 case 38: return &( settings->rom_spec_se_0 ); 757 case 39: return &( settings->rom_spec_se_1 ); 758 default: return NULL; 759 } 760 } else { 761 switch( which ) { 762 case 0: return &( settings->rom_interface_1 ); 763 case 1: return &( settings->rom_beta128 ); 764 case 2: return &( settings->rom_plusd ); 765 case 3: return &( settings->rom_didaktik80 ); 766 case 4: return &( settings->rom_disciple ); 767 case 5: return &( settings->rom_multiface1 ); 768 case 6: return &( settings->rom_multiface128 ); 769 case 7: return &( settings->rom_multiface3 ); 770 case 8: return &( settings->rom_opus ); 771 case 9: return &( settings->rom_speccyboot ); 772 case 10: return &( settings->rom_ttx2000s ); 773 case 11: return &( settings->rom_usource ); 774 default: return NULL; 775 } 776 } 777} 778 779void 780settings_set_string( char **string_setting, const char *value ) 781{ 782 /* No need to do anything if the two strings are in fact the 783 same pointer */ 784 if( *string_setting == value ) return; 785 786 if( *string_setting ) libspectrum_free( *string_setting ); 787 *string_setting = utils_safe_strdup( value ); 788} 789 790int 791settings_free( settings_info *settings ) 792{ 793CODE 794 795foreach my $name ( sort keys %options ) { 796 if( $options{$name}->{type} eq 'string' ) { 797 print " if( settings->$name ) libspectrum_free( settings->$name );\n"; 798 } 799} 800 801print hashline( __LINE__ ), << 'CODE'; 802 803 return 0; 804} 805 806static void 807settings_end( void ) 808{ 809 if( settings_current.autosave_settings ) 810 settings_write_config( &settings_current ); 811 812 settings_free( &settings_current ); 813 814#ifdef HAVE_LIB_XML2 815 xmlCleanupParser(); 816#endif /* #ifdef HAVE_LIB_XML2 */ 817} 818 819void 820settings_register_startup( void ) 821{ 822 /* settings_init not yet managed by the startup manager */ 823 824 startup_manager_module dependencies[] = { 825 /* Fuse for OS X requires that settings_end is called before memory is 826 deallocated as settings need to look up machine names etc */ 827 /* STARTUP_MANAGER_MODULE_MEMORY, */ 828 STARTUP_MANAGER_MODULE_SETUID, 829 }; 830 startup_manager_register( STARTUP_MANAGER_MODULE_SETTINGS_END, dependencies, 831 ARRAY_SIZE( dependencies ), NULL, NULL, 832 settings_end ); 833} 834 835CODE 836