/* fuse.c: The Free Unix Spectrum Emulator Copyright (c) 1999-2007 Philip Kendall $Id: fuse.c,v 1.133.2.3 2007/04/11 09:39:32 pak21 Exp $ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Author contact information: E-mail: philip-fuse@shadowmagic.org.uk */ #include #include #include #include #include #include #ifndef WIN32 #include #else /* #ifndef WIN32 */ #include #endif /* #ifndef WIN32 */ #include #ifdef UI_SDL #include /* Needed on MacOS X and Windows */ #endif /* #ifdef UI_SDL */ #include "dck.h" #include "debugger/debugger.h" #include "display.h" #include "divide.h" #include "event.h" #include "fuse.h" #include "if1.h" #include "joystick.h" #include "keyboard.h" #include "machine.h" #include "memory.h" #include "pokefinder/pokefinder.h" #include "printer.h" #include "psg.h" #include "rzx.h" #include "settings.h" #include "simpleide.h" #include "snapshot.h" #include "sound.h" #include "sound/lowlevel.h" #include "spectrum.h" #include "tape.h" #include "timer.h" #include "trdos.h" #include "ui/ui.h" #include "ui/scaler/scaler.h" #include "utils.h" #include "zxatasp.h" #include "zxcf.h" #ifdef USE_WIDGET #include "widget/widget.h" #endif /* #ifdef USE_WIDGET */ #include "z80/z80.h" /* What name were we called under? */ char *fuse_progname; /* Which directory were we started in? */ char fuse_directory[ PATH_MAX ]; /* A flag to say when we want to exit the emulator */ int fuse_exiting; /* Is Spectrum emulation currently paused, and if so, how many times? */ int fuse_emulation_paused; /* The creator information we'll store in file formats that support this */ libspectrum_creator *fuse_creator; /* The earliest version of libspectrum we need */ static const char *LIBSPECTRUM_MIN_VERSION = "0.2.0.1"; /* The various types of file we may want to run on startup */ typedef struct start_files_t { const char *disk_plus3; const char *disk_trdos; const char *dock; const char *if2; const char *playback; const char *recording; const char *snapshot; const char *tape; const char *simpleide_master, *simpleide_slave; const char *zxatasp_master, *zxatasp_slave; const char *zxcf; const char *divide_master, *divide_slave; const char *mdr[8]; } start_files_t; static int fuse_init(int argc, char **argv); static int creator_init( void ); static void fuse_show_copyright(void); static void fuse_show_version( void ); static void fuse_show_help( void ); static int setup_start_files( start_files_t *start_files ); static int parse_nonoption_args( int argc, char **argv, int first_arg, start_files_t *start_files ); static int do_start_files( start_files_t *start_files ); static int fuse_end(void); int main(int argc, char **argv) { if(fuse_init(argc,argv)) { fprintf(stderr,"%s: error initialising -- giving up!\n", fuse_progname); return 1; } if( settings_current.show_help || settings_current.show_version ) return 0; while( !fuse_exiting ) { z80_do_opcodes(); event_do_events(); } fuse_end(); return 0; } static int fuse_init(int argc, char **argv) { int error, first_arg; char *start_scaler; start_files_t start_files; fuse_progname=argv[0]; libspectrum_error_function = ui_libspectrum_error; if( !getcwd( fuse_directory, PATH_MAX - 1 ) ) { ui_error( UI_ERROR_ERROR, "error getting current working directory: %s", strerror( errno ) ); return 1; } strcat( fuse_directory, "/" ); if( settings_init( &first_arg, argc, argv ) ) return 1; if( settings_current.show_version ) { fuse_show_version(); return 0; } else if( settings_current.show_help ) { fuse_show_help(); return 0; } start_scaler = strdup( settings_current.start_scaler_mode ); if( !start_scaler ) { ui_error( UI_ERROR_ERROR, "Out of memory at %s: %d", __FILE__, __LINE__ ); return 1; } fuse_show_copyright(); /* FIXME: order of these initialisation calls. Work out what depends on what */ /* FIXME FIXME 20030407: really do this soon. This is getting *far* too hairy */ fuse_joystick_init (); fuse_keyboard_init(); #ifdef USE_WIDGET if( widget_init() ) return 1; #endif /* #ifdef USE_WIDGET */ if( event_init() ) return 1; if( display_init(&argc,&argv) ) return 1; if( libspectrum_check_version( LIBSPECTRUM_MIN_VERSION ) ) { if( libspectrum_init() ) return 1; } else { ui_error( UI_ERROR_ERROR, "libspectrum version %s found, but %s required", libspectrum_version(), LIBSPECTRUM_MIN_VERSION ); return 1; } /* Must be called after libspectrum_init() so we can get the gcrypt version */ if( creator_init() ) return 1; #ifdef HAVE_GETEUID /* Drop root privs if we have them */ if( !geteuid() ) { setuid( getuid() ); } #endif /* #ifdef HAVE_GETEUID */ if( memory_init() ) return 1; if( debugger_init() ) return 1; if( printer_init() ) return 1; if( rzx_init() ) return 1; if( psg_init() ) return 1; if( trdos_init() ) return 1; if( simpleide_init() ) return 1; if( zxatasp_init() ) return 1; if( zxcf_init() ) return 1; if( if1_init() ) return 1; if( divide_init() ) return 1; error = pokefinder_clear(); if( error ) return error; z80_init(); if( timer_init() ) return 1; error = timer_estimate_reset(); if( error ) return error; error = machine_init_machines(); if( error ) return error; error = machine_select_id( settings_current.start_machine ); if( error ) return error; error = tape_init(); if( error ) return error; error = scaler_select_id( start_scaler ); free( start_scaler ); if( error ) return error; if( setup_start_files( &start_files ) ) return 1; if( parse_nonoption_args( argc, argv, first_arg, &start_files ) ) return 1; if( do_start_files( &start_files ) ) return 1; if( ui_mouse_present ) ui_mouse_grabbed = ui_mouse_grab( 1 ); fuse_emulation_paused = 0; return 0; } static int creator_init( void ) { size_t i; unsigned int version[4] = { 0, 0, 0, 0 }; char *custom; #ifndef WIN32 struct utsname buf; #else /* #ifndef WIN32 */ OSVERSIONINFO buf; char *windows_name; #endif /* #ifndef WIN32 */ libspectrum_error error; int sys_error; const char *gcrypt_version; sscanf( VERSION, "%u.%u.%u.%u", &version[0], &version[1], &version[2], &version[3] ); for( i=0; i<4; i++ ) if( version[i] > 0xff ) version[i] = 0xff; #ifndef WIN32 sys_error = uname( &buf ); if( sys_error == -1 ) { ui_error( UI_ERROR_ERROR, "error getting system information: %s", strerror( errno ) ); return 1; } #else /* #ifndef WIN32 */ buf.dwOSVersionInfoSize = sizeof( buf ); sys_error = GetVersionEx( &buf ); if( sys_error == 0 ) { ui_error( UI_ERROR_ERROR, "error getting system information." ); return 1; } #endif /* #ifndef WIN32 */ error = libspectrum_creator_alloc( &fuse_creator ); if( error ) return error; error = libspectrum_creator_set_program( fuse_creator, "Fuse" ); if( error ) { libspectrum_creator_free( fuse_creator ); return error; } error = libspectrum_creator_set_major( fuse_creator, version[0] * 0x100 + version[1] ); if( error ) { libspectrum_creator_free( fuse_creator ); return error; } error = libspectrum_creator_set_minor( fuse_creator, version[2] * 0x100 + version[3] ); if( error ) { libspectrum_creator_free( fuse_creator ); return error; } custom = malloc( 256 ); if( !custom ) { ui_error( UI_ERROR_ERROR, "out of memory at %s:%d", __FILE__, __LINE__ ); libspectrum_creator_free( fuse_creator ); return 1; } gcrypt_version = libspectrum_gcrypt_version(); if( !gcrypt_version ) gcrypt_version = "not available"; #ifndef WIN32 snprintf( custom, 256, "gcrypt: %s\nlibspectrum: %s\nuname: %s %s %s", gcrypt_version, libspectrum_version(), buf.sysname, buf.machine, buf.release ); #else /* #ifndef WIN32 */ switch( buf.dwPlatformId ) { case VER_PLATFORM_WIN32_NT: windows_name = "NT"; break; case VER_PLATFORM_WIN32_WINDOWS: windows_name = "95/98"; break; case VER_PLATFORM_WIN32s: windows_name = "3.1"; break; default: windows_name = "unknown"; break; } snprintf( custom, 256, "gcrypt: %s\nlibspectrum: %s\nuname: Windows %s %d.%d build %d %s", gcrypt_version, libspectrum_version(), windows_name, buf.dwMajorVersion, buf.dwMinorVersion, buf.dwBuildNumber, buf.szCSDVersion ); #endif /* #ifndef WIN32 */ error = libspectrum_creator_set_custom( fuse_creator, (libspectrum_byte*)custom, strlen( custom ) ); if( error ) { free( custom ); libspectrum_creator_free( fuse_creator ); return error; } return 0; } static void fuse_show_copyright(void) { printf( "\n" ); fuse_show_version(); printf( "Copyright (c) 1999-2007 Philip Kendall \n" "and others; see the file 'AUTHORS' for more details.\n" "\n" "This program is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "GNU General Public License for more details.\n\n"); } static void fuse_show_version( void ) { printf( "The Free Unix Spectrum Emulator (Fuse) version " VERSION ".\n" ); } static void fuse_show_help( void ) { printf( "\n" ); fuse_show_version(); printf( "\nAvailable command-line options:\n\n" "Boolean options (use `--no-