X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=source%2Ffront-end%2Fsrc%2Fmain.c;fp=source%2Ffront-end%2Fsrc%2Fmain.c;h=a0ff193bb8cf7d9ffa201a204f78a96a338d1cf2;hb=5288f5429f38c99c73856e285d35e7d0c4c779d0;hp=0000000000000000000000000000000000000000;hpb=48d77f736bea02afeb362cff05c81375752b3015;p=mupen64plus-pandora.git diff --git a/source/front-end/src/main.c b/source/front-end/src/main.c new file mode 100755 index 0000000..a0ff193 --- /dev/null +++ b/source/front-end/src/main.c @@ -0,0 +1,819 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Mupen64plus-ui-console - main.c * + * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * + * Copyright (C) 2007-2010 Richard42 * + * Copyright (C) 2008 Ebenblues Nmn Okaygo Tillin9 * + * Copyright (C) 2002 Hacktarux * + * * + * 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* This is the main application entry point for the console-only front-end + * for Mupen64Plus v2.0. + */ + +#include +#include +#include +#include + +#include + +#include "cheat.h" +#include "main.h" +#include "plugin.h" +#include "version.h" +#include "core_interface.h" +#include "compare_core.h" +#include "osal_preproc.h" + +#ifdef PAULSCODE +//#include "ae_bridge.h" +#endif + +/* Version number for UI-Console config section parameters */ +#define CONFIG_PARAM_VERSION 1.00 + +/** global variables **/ +int g_Verbose = 0; + +/** static (local) variables **/ +static m64p_handle l_ConfigCore = NULL; +static m64p_handle l_ConfigVideo = NULL; +static m64p_handle l_ConfigUI = NULL; + +static const char *l_CoreLibPath = NULL; +static const char *l_ConfigDirPath = NULL; +static const char *l_ROMFilepath = NULL; // filepath of ROM to load & run at startup + +#if defined(SHAREDIR) + static const char *l_DataDirPath = SHAREDIR; +#else + static const char *l_DataDirPath = NULL; +#endif + +static int *l_TestShotList = NULL; // list of screenshots to take for regression test support +static int l_TestShotIdx = 0; // index of next screenshot frame in list +static int l_SaveOptions = 1; // save command-line options in configuration file (enabled by default) +static int l_CoreCompareMode = 0; // 0 = disable, 1 = send, 2 = receive + +static eCheatMode l_CheatMode = CHEAT_DISABLE; +static char *l_CheatNumList = NULL; + +/********************************************************************************************************* + * Callback functions from the core + */ + +void DebugMessage(int level, const char *message, ...) +{ + char msgbuf[1024]; + va_list args; + + va_start(args, message); + vsnprintf(msgbuf, 1024, message, args); + + DebugCallback("UI-Console", level, msgbuf); + + va_end(args); +} + +void DebugCallback(void *Context, int level, const char *message) +{ +#ifdef ANDROID0 + if (level == M64MSG_ERROR) + __android_log_print(ANDROID_LOG_ERROR, (const char *) Context, "%s", message); + else if (level == M64MSG_WARNING) + __android_log_print(ANDROID_LOG_WARN, (const char *) Context, "%s", message); + else if (level == M64MSG_INFO) + __android_log_print(ANDROID_LOG_INFO, (const char *) Context, "%s", message); + else if (level == M64MSG_STATUS) + __android_log_print(ANDROID_LOG_DEBUG, (const char *) Context, "%s", message); + else if (level == M64MSG_VERBOSE) + { + if (g_Verbose) + __android_log_print(ANDROID_LOG_VERBOSE, (const char *) Context, "%s", message); + } + else + __android_log_print(ANDROID_LOG_ERROR, (const char *) Context, "Unknown: %s", message); +#else + if (level == M64MSG_ERROR) + printf("%s Error: %s\n", (const char *) Context, message); + else if (level == M64MSG_WARNING) + printf("%s Warning: %s\n", (const char *) Context, message); + else if (level == M64MSG_INFO) + printf("%s: %s\n", (const char *) Context, message); + else if (level == M64MSG_STATUS) + printf("%s Status: %s\n", (const char *) Context, message); + else if (level == M64MSG_VERBOSE) + { + if (g_Verbose) + printf("%s: %s\n", (const char *) Context, message); + } + else + printf("%s Unknown: %s\n", (const char *) Context, message); +#endif +} + +static void FrameCallback(unsigned int FrameIndex) +{ + // take a screenshot if we need to + if (l_TestShotList != NULL) + { + int nextshot = l_TestShotList[l_TestShotIdx]; + if (nextshot == FrameIndex) + { + (*CoreDoCommand)(M64CMD_TAKE_NEXT_SCREENSHOT, 0, NULL); /* tell the core take a screenshot */ + // advance list index to next screenshot frame number. If it's 0, then quit + l_TestShotIdx++; + } + else if (nextshot == 0) + { + (*CoreDoCommand)(M64CMD_STOP, 0, NULL); /* tell the core to shut down ASAP */ + free(l_TestShotList); + l_TestShotList = NULL; + } + } +} + +#ifdef PAULSCODE +void StateCallback( void *Context, m64p_core_param ParamChanged, int NewValue ) +{ + /*----ParamChanged----------------- + * --------NewValue-------- + * M64CORE_EMU_STATE 1 + * M64EMU_STOPPED 1 + * M64EMU_RUNNING 2 + * M64EMU_PAUSED 3 + * M64CORE_VIDEO_MODE 2 + * M64CORE_SAVESTATE_SLOT 3 + * M64CORE_SPEED_FACTOR 4 + * M64CORE_SPEED_LIMITER 5 + * M64CORE_VIDEO_SIZE 6 + * M64CORE_AUDIO_VOLUME 7 + * M64CORE_AUDIO_MUTE 8 + * M64CORE_INPUT_GAMESHARK 9 + * M64CORE_STATE_LOADCOMPLETE 10 + * (successful) 1 + * (unsuccessful) 0 + * M64CORE_STATE_SAVECOMPLETE 11 + * (successful) 1 + * (unsuccessful) 0 + */ + + if( ParamChanged == M64CORE_EMU_STATE || ParamChanged == M64CORE_STATE_SAVECOMPLETE || ParamChanged == M64CORE_STATE_LOADCOMPLETE ) + Android_JNI_State_Callback( ParamChanged, NewValue ); +} +#endif + +/********************************************************************************************************* + * Configuration handling + */ + +static m64p_error OpenConfigurationHandles(void) +{ + float fConfigParamsVersion; + int bSaveConfig = 0; + m64p_error rval; + + /* Open Configuration sections for core library and console User Interface */ + rval = (*ConfigOpenSection)("Core", &l_ConfigCore); + if (rval != M64ERR_SUCCESS) + { + DebugMessage(M64MSG_ERROR, "failed to open 'Core' configuration section"); + return rval; + } + + rval = (*ConfigOpenSection)("Video-General", &l_ConfigVideo); + if (rval != M64ERR_SUCCESS) + { + DebugMessage(M64MSG_ERROR, "failed to open 'Video-General' configuration section"); + return rval; + } + + rval = (*ConfigOpenSection)("UI-Console", &l_ConfigUI); + if (rval != M64ERR_SUCCESS) + { + DebugMessage(M64MSG_ERROR, "failed to open 'UI-Console' configuration section"); + return rval; + } + + if ((*ConfigGetParameter)(l_ConfigUI, "Version", M64TYPE_FLOAT, &fConfigParamsVersion, sizeof(float)) != M64ERR_SUCCESS) + { + DebugMessage(M64MSG_WARNING, "No version number in 'UI-Console' config section. Setting defaults."); + (*ConfigDeleteSection)("UI-Console"); + (*ConfigOpenSection)("UI-Console", &l_ConfigUI); + bSaveConfig = 1; + } + else if (((int) fConfigParamsVersion) != ((int) CONFIG_PARAM_VERSION)) + { + DebugMessage(M64MSG_WARNING, "Incompatible version %.2f in 'UI-Console' config section: current is %.2f. Setting defaults.", fConfigParamsVersion, (float) CONFIG_PARAM_VERSION); + (*ConfigDeleteSection)("UI-Console"); + (*ConfigOpenSection)("UI-Console", &l_ConfigUI); + bSaveConfig = 1; + } + else if ((CONFIG_PARAM_VERSION - fConfigParamsVersion) >= 0.0001f) + { + /* handle upgrades */ + float fVersion = CONFIG_PARAM_VERSION; + ConfigSetParameter(l_ConfigUI, "Version", M64TYPE_FLOAT, &fVersion); + DebugMessage(M64MSG_INFO, "Updating parameter set version in 'UI-Console' config section to %.2f", fVersion); + bSaveConfig = 1; + } + + /* Set default values for my Config parameters */ + (*ConfigSetDefaultFloat)(l_ConfigUI, "Version", CONFIG_PARAM_VERSION, "Mupen64Plus UI-Console config parameter set version number. Please don't change this version number."); + (*ConfigSetDefaultString)(l_ConfigUI, "PluginDir", OSAL_CURRENT_DIR, "Directory in which to search for plugins"); + (*ConfigSetDefaultString)(l_ConfigUI, "VideoPlugin", "mupen64plus-video-rice" OSAL_DLL_EXTENSION, "Filename of video plugin"); + (*ConfigSetDefaultString)(l_ConfigUI, "AudioPlugin", "mupen64plus-audio-sdl" OSAL_DLL_EXTENSION, "Filename of audio plugin"); + (*ConfigSetDefaultString)(l_ConfigUI, "InputPlugin", "mupen64plus-input-sdl" OSAL_DLL_EXTENSION, "Filename of input plugin"); + (*ConfigSetDefaultString)(l_ConfigUI, "RspPlugin", "mupen64plus-rsp-hle" OSAL_DLL_EXTENSION, "Filename of RSP plugin"); + + if (bSaveConfig && ConfigSaveSection != NULL) /* ConfigSaveSection was added in Config API v2.1.0 */ + (*ConfigSaveSection)("UI-Console"); + + return M64ERR_SUCCESS; +} + +static m64p_error SaveConfigurationOptions(void) +{ + /* if shared data directory was given on the command line, write it into the config file */ + if (l_DataDirPath != NULL) + (*ConfigSetParameter)(l_ConfigCore, "SharedDataPath", M64TYPE_STRING, l_DataDirPath); + + /* if any plugin filepaths were given on the command line, write them into the config file */ + if (g_PluginDir != NULL) + (*ConfigSetParameter)(l_ConfigUI, "PluginDir", M64TYPE_STRING, g_PluginDir); + if (g_GfxPlugin != NULL) + (*ConfigSetParameter)(l_ConfigUI, "VideoPlugin", M64TYPE_STRING, g_GfxPlugin); + if (g_AudioPlugin != NULL) + (*ConfigSetParameter)(l_ConfigUI, "AudioPlugin", M64TYPE_STRING, g_AudioPlugin); + if (g_InputPlugin != NULL) + (*ConfigSetParameter)(l_ConfigUI, "InputPlugin", M64TYPE_STRING, g_InputPlugin); + if (g_RspPlugin != NULL) + (*ConfigSetParameter)(l_ConfigUI, "RspPlugin", M64TYPE_STRING, g_RspPlugin); + + return (*ConfigSaveFile)(); +} + +/********************************************************************************************************* + * Command-line parsing + */ + +static void printUsage(const char *progname) +{ + printf("Usage: %s [parameters] [romfile]\n" + "\n" + "Parameters:\n" + " --noosd : disable onscreen display\n" + " --osd : enable onscreen display\n" + " --fullscreen : use fullscreen display mode\n" + " --windowed : use windowed display mode\n" + " --resolution (res) : display resolution (640x480, 800x600, 1024x768, etc)\n" + " --nospeedlimit : disable core speed limiter (should be used with dummy audio plugin)\n" + " --cheats (cheat-spec) : enable or list cheat codes for the given rom file\n" + " --corelib (filepath) : use core library (filepath) (can be only filename or full path)\n" + " --configdir (dir) : force configation directory to (dir); should contain mupen64plus.cfg\n" + " --datadir (dir) : search for shared data files (.ini files, languages, etc) in (dir)\n" + " --plugindir (dir) : search for plugins in (dir)\n" + " --sshotdir (dir) : set screenshot directory to (dir)\n" + " --gfx (plugin-spec) : use gfx plugin given by (plugin-spec)\n" + " --audio (plugin-spec) : use audio plugin given by (plugin-spec)\n" + " --input (plugin-spec) : use input plugin given by (plugin-spec)\n" + " --rsp (plugin-spec) : use rsp plugin given by (plugin-spec)\n" + " --emumode (mode) : set emu mode to: 0=Pure Interpreter 1=Interpreter 2=DynaRec\n" + " --testshots (list) : take screenshots at frames given in comma-separated (list), then quit\n" + " --set (param-spec) : set a configuration variable, format: ParamSection[ParamName]=Value\n" + " --core-compare-send : use the Core Comparison debugging feature, in data sending mode\n" + " --core-compare-recv : use the Core Comparison debugging feature, in data receiving mode\n" + " --nosaveoptions : do not save the given command-line options in configuration file\n" + " --verbose : print lots of information\n" + " --help : see this help message\n\n" + "(plugin-spec):\n" + " (pluginname) : filename (without path) of plugin to find in plugin directory\n" + " (pluginpath) : full path and filename of plugin\n" + " 'dummy' : use dummy plugin\n\n" + "(cheat-spec):\n" + " 'list' : show all of the available cheat codes\n" + " 'all' : enable all of the available cheat codes\n" + " (codelist) : a comma-separated list of cheat code numbers to enable,\n" + " with dashes to use code variables (ex 1-2 to use cheat 1 option 2)\n" + "\n", progname); + + return; +} + +static int SetConfigParameter(const char *ParamSpec) +{ + char *ParsedString, *VarName, *VarValue=NULL; + m64p_handle ConfigSection; + m64p_type VarType; + m64p_error rval; + + if (ParamSpec == NULL) + { + DebugMessage(M64MSG_ERROR, "ParamSpec is NULL in SetConfigParameter()"); + return 1; + } + + /* make a copy of the input string */ + ParsedString = (char *) malloc(strlen(ParamSpec) + 1); + if (ParsedString == NULL) + { + DebugMessage(M64MSG_ERROR, "SetConfigParameter() couldn't allocate memory for temporary string."); + return 2; + } + strcpy(ParsedString, ParamSpec); + + /* parse it for the simple section[name]=value format */ + VarName = strchr(ParsedString, '['); + if (VarName != NULL) + { + *VarName++ = 0; + VarValue = strchr(VarName, ']'); + if (VarValue != NULL) + { + *VarValue++ = 0; + } + } + if (VarName == NULL || VarValue == NULL || *VarValue != '=') + { + DebugMessage(M64MSG_ERROR, "invalid (param-spec) '%s'", ParamSpec); + free(ParsedString); + return 3; + } + VarValue++; + + /* then set the value */ + rval = (*ConfigOpenSection)(ParsedString, &ConfigSection); + if (rval != M64ERR_SUCCESS) + { + DebugMessage(M64MSG_ERROR, "SetConfigParameter failed to open config section '%s'", ParsedString); + free(ParsedString); + return 4; + } + if ((*ConfigGetParameterType)(ConfigSection, VarName, &VarType) == M64ERR_SUCCESS) + { + switch(VarType) + { + int ValueInt; + float ValueFloat; + case M64TYPE_INT: + ValueInt = atoi(VarValue); + ConfigSetParameter(ConfigSection, VarName, M64TYPE_INT, &ValueInt); + break; + case M64TYPE_FLOAT: + ValueFloat = (float) atof(VarValue); + ConfigSetParameter(ConfigSection, VarName, M64TYPE_FLOAT, &ValueFloat); + break; + case M64TYPE_BOOL: + ValueInt = (int) (osal_insensitive_strcmp(VarValue, "true") == 0); + ConfigSetParameter(ConfigSection, VarName, M64TYPE_BOOL, &ValueInt); + break; + case M64TYPE_STRING: + ConfigSetParameter(ConfigSection, VarName, M64TYPE_STRING, VarValue); + break; + default: + DebugMessage(M64MSG_ERROR, "invalid VarType in SetConfigParameter()"); + return 5; + } + } + else + { + ConfigSetParameter(ConfigSection, VarName, M64TYPE_STRING, VarValue); + } + + free(ParsedString); + return 0; +} + +static int *ParseNumberList(const char *InputString, int *ValuesFound) +{ + const char *str; + int *OutputList; + + /* count the number of integers in the list */ + int values = 1; + str = InputString; + while ((str = strchr(str, ',')) != NULL) + { + str++; + values++; + } + + /* create a list and populate it with the frame counter values at which to take screenshots */ + if ((OutputList = (int *) malloc(sizeof(int) * (values + 1))) != NULL) + { + int idx = 0; + str = InputString; + while (str != NULL) + { + OutputList[idx++] = atoi(str); + str = strchr(str, ','); + if (str != NULL) str++; + } + OutputList[idx] = 0; + } + + if (ValuesFound != NULL) + *ValuesFound = values; + return OutputList; +} + +static int ParseCommandLineInitial(int argc, const char **argv) +{ + int i; + + /* look through commandline options */ + for (i = 1; i < argc; i++) + { + int ArgsLeft = argc - i - 1; + + if (strcmp(argv[i], "--corelib") == 0 && ArgsLeft >= 1) + { + l_CoreLibPath = argv[i+1]; + i++; + } + else if (strcmp(argv[i], "--configdir") == 0 && ArgsLeft >= 1) + { + l_ConfigDirPath = argv[i+1]; + i++; + } + else if (strcmp(argv[i], "--datadir") == 0 && ArgsLeft >= 1) + { + l_DataDirPath = argv[i+1]; + i++; + } + else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) + { + printUsage(argv[0]); + return 1; + } + } + + return 0; +} + +static m64p_error ParseCommandLineFinal(int argc, const char **argv) +{ + int i; + + /* parse commandline options */ + for (i = 1; i < argc; i++) + { + int ArgsLeft = argc - i - 1; + if (strcmp(argv[i], "--noosd") == 0) + { + int Osd = 0; + (*ConfigSetParameter)(l_ConfigCore, "OnScreenDisplay", M64TYPE_BOOL, &Osd); + } + else if (strcmp(argv[i], "--osd") == 0) + { + int Osd = 1; + (*ConfigSetParameter)(l_ConfigCore, "OnScreenDisplay", M64TYPE_BOOL, &Osd); + } + else if (strcmp(argv[i], "--fullscreen") == 0) + { + int Fullscreen = 1; + (*ConfigSetParameter)(l_ConfigVideo, "Fullscreen", M64TYPE_BOOL, &Fullscreen); + } + else if (strcmp(argv[i], "--windowed") == 0) + { + int Fullscreen = 0; + (*ConfigSetParameter)(l_ConfigVideo, "Fullscreen", M64TYPE_BOOL, &Fullscreen); + } + else if (strcmp(argv[i], "--nospeedlimit") == 0) + { + int EnableSpeedLimit = 0; + if (g_CoreAPIVersion < 0x020001) + DebugMessage(M64MSG_WARNING, "core library doesn't support --nospeedlimit"); + else + { + if ((*CoreDoCommand)(M64CMD_CORE_STATE_SET, M64CORE_SPEED_LIMITER, &EnableSpeedLimit) != M64ERR_SUCCESS) + DebugMessage(M64MSG_ERROR, "core gave error while setting --nospeedlimit option"); + } + } + else if ((strcmp(argv[i], "--corelib") == 0 || strcmp(argv[i], "--configdir") == 0 || + strcmp(argv[i], "--datadir") == 0) && ArgsLeft >= 1) + { /* these are handled in ParseCommandLineInitial */ + i++; + } + else if (strcmp(argv[i], "--resolution") == 0 && ArgsLeft >= 1) + { + const char *res = argv[i+1]; + int xres, yres; + i++; + if (sscanf(res, "%ix%i", &xres, &yres) != 2) + DebugMessage(M64MSG_WARNING, "couldn't parse resolution '%s'", res); + else + { + (*ConfigSetParameter)(l_ConfigVideo, "ScreenWidth", M64TYPE_INT, &xres); + (*ConfigSetParameter)(l_ConfigVideo, "ScreenHeight", M64TYPE_INT, &yres); + } + } + else if (strcmp(argv[i], "--cheats") == 0 && ArgsLeft >= 1) + { + if (strcmp(argv[i+1], "all") == 0) + l_CheatMode = CHEAT_ALL; + else if (strcmp(argv[i+1], "list") == 0) + l_CheatMode = CHEAT_SHOW_LIST; + else + { + l_CheatMode = CHEAT_LIST; + l_CheatNumList = (char*) argv[i+1]; + } + i++; + } + else if (strcmp(argv[i], "--plugindir") == 0 && ArgsLeft >= 1) + { + g_PluginDir = argv[i+1]; + i++; + } + else if (strcmp(argv[i], "--sshotdir") == 0 && ArgsLeft >= 1) + { + (*ConfigSetParameter)(l_ConfigCore, "ScreenshotPath", M64TYPE_STRING, argv[i+1]); + i++; + } + else if (strcmp(argv[i], "--gfx") == 0 && ArgsLeft >= 1) + { + g_GfxPlugin = argv[i+1]; + i++; + } + else if (strcmp(argv[i], "--audio") == 0 && ArgsLeft >= 1) + { + g_AudioPlugin = argv[i+1]; + i++; + } + else if (strcmp(argv[i], "--input") == 0 && ArgsLeft >= 1) + { + g_InputPlugin = argv[i+1]; + i++; + } + else if (strcmp(argv[i], "--rsp") == 0 && ArgsLeft >= 1) + { + g_RspPlugin = argv[i+1]; + i++; + } + else if (strcmp(argv[i], "--emumode") == 0 && ArgsLeft >= 1) + { + int emumode = atoi(argv[i+1]); + i++; + if (emumode < 0 || emumode > 2) + { + DebugMessage(M64MSG_WARNING, "invalid --emumode value '%i'", emumode); + continue; + } + if (emumode == 2 && !(g_CoreCapabilities & M64CAPS_DYNAREC)) + { + DebugMessage(M64MSG_WARNING, "Emulator core doesn't support Dynamic Recompiler."); + emumode = 1; + } + (*ConfigSetParameter)(l_ConfigCore, "R4300Emulator", M64TYPE_INT, &emumode); + } + else if (strcmp(argv[i], "--testshots") == 0 && ArgsLeft >= 1) + { + l_TestShotList = ParseNumberList(argv[i+1], NULL); + i++; + } + else if (strcmp(argv[i], "--set") == 0 && ArgsLeft >= 1) + { + if (SetConfigParameter(argv[i+1]) != 0) + return M64ERR_INPUT_INVALID; + i++; + } + else if (strcmp(argv[i], "--core-compare-send") == 0) + { + l_CoreCompareMode = 1; + } + else if (strcmp(argv[i], "--core-compare-recv") == 0) + { + l_CoreCompareMode = 2; + } + else if (strcmp(argv[i], "--nosaveoptions") == 0) + { + l_SaveOptions = 0; + } + else if (ArgsLeft == 0) + { + /* this is the last arg, it should be a ROM filename */ + l_ROMFilepath = argv[i]; + return M64ERR_SUCCESS; + } + else if (strcmp(argv[i], "--verbose") == 0) + { + g_Verbose = 1; + } + else + { + DebugMessage(M64MSG_WARNING, "unrecognized command-line parameter '%s'", argv[i]); + } + /* continue argv loop */ + } + + /* missing ROM filepath */ + DebugMessage(M64MSG_ERROR, "no ROM filepath given"); + return M64ERR_INPUT_INVALID; +} + +/********************************************************************************************************* +* main function +*/ +int main(int argc, char *argv[]) +{ + int i; + + printf(" __ __ __ _ _ ____ _ \n"); + printf("| \\/ |_ _ _ __ ___ _ __ / /_ | || | | _ \\| |_ _ ___ \n"); + printf("| |\\/| | | | | '_ \\ / _ \\ '_ \\| '_ \\| || |_| |_) | | | | / __| \n"); + printf("| | | | |_| | |_) | __/ | | | (_) |__ _| __/| | |_| \\__ \\ \n"); + printf("|_| |_|\\__,_| .__/ \\___|_| |_|\\___/ |_| |_| |_|\\__,_|___/ \n"); + printf(" |_| http://code.google.com/p/mupen64plus/ \n"); + printf("%s Version %i.%i.%i\n\n", CONSOLE_UI_NAME, VERSION_PRINTF_SPLIT(CONSOLE_UI_VERSION)); + + /* bootstrap some special parameters from the command line */ + if (ParseCommandLineInitial(argc, (const char **) argv) != 0) + return 1; + + /* load the Mupen64Plus core library */ + if (AttachCoreLib(l_CoreLibPath) != M64ERR_SUCCESS) + return 2; + + /* start the Mupen64Plus core library, load the configuration file */ + #ifdef PAULSCODE + m64p_error rval = (*CoreStartup)( CORE_API_VERSION, l_ConfigDirPath, l_DataDirPath, "Core", DebugCallback, NULL, StateCallback ); + #else + m64p_error rval = (*CoreStartup)(CORE_API_VERSION, l_ConfigDirPath, l_DataDirPath, "Core", DebugCallback, NULL, NULL); + #endif + if (rval != M64ERR_SUCCESS) + { + DebugMessage(M64MSG_ERROR, "couldn't start Mupen64Plus core library."); + DetachCoreLib(); + return 3; + } + + /* Open configuration sections */ + rval = OpenConfigurationHandles(); + if (rval != M64ERR_SUCCESS) + { + (*CoreShutdown)(); + DetachCoreLib(); + return 4; + } + + /* parse command-line options */ + rval = ParseCommandLineFinal(argc, (const char **) argv); + if (rval != M64ERR_SUCCESS) + { + (*CoreShutdown)(); + DetachCoreLib(); + return 5; + } + + /* Handle the core comparison feature */ + if (l_CoreCompareMode != 0 && !(g_CoreCapabilities & M64CAPS_CORE_COMPARE)) + { + DebugMessage(M64MSG_ERROR, "can't use --core-compare feature with this Mupen64Plus core library."); + DetachCoreLib(); + return 6; + } + compare_core_init(l_CoreCompareMode); + + /* save the given command-line options in configuration file if requested */ + if (l_SaveOptions) + SaveConfigurationOptions(); + + /* load ROM image */ + FILE *fPtr = fopen(l_ROMFilepath, "rb"); + if (fPtr == NULL) + { + DebugMessage(M64MSG_ERROR, "couldn't open ROM file '%s' for reading.", l_ROMFilepath); + (*CoreShutdown)(); + DetachCoreLib(); + return 7; + } + + /* get the length of the ROM, allocate memory buffer, load it from disk */ + long romlength = 0; + fseek(fPtr, 0L, SEEK_END); + romlength = ftell(fPtr); + fseek(fPtr, 0L, SEEK_SET); + unsigned char *ROM_buffer = (unsigned char *) malloc(romlength); + if (ROM_buffer == NULL) + { + DebugMessage(M64MSG_ERROR, "couldn't allocate %li-byte buffer for ROM image file '%s'.", romlength, l_ROMFilepath); + fclose(fPtr); + (*CoreShutdown)(); + DetachCoreLib(); + return 8; + } + else if (fread(ROM_buffer, 1, romlength, fPtr) != romlength) + { + DebugMessage(M64MSG_ERROR, "couldn't read %li bytes from ROM image file '%s'.", romlength, l_ROMFilepath); + free(ROM_buffer); + fclose(fPtr); + (*CoreShutdown)(); + DetachCoreLib(); + return 9; + } + fclose(fPtr); + + /* Try to load the ROM image into the core */ + if ((*CoreDoCommand)(M64CMD_ROM_OPEN, (int) romlength, ROM_buffer) != M64ERR_SUCCESS) + { + DebugMessage(M64MSG_ERROR, "core failed to open ROM image file '%s'.", l_ROMFilepath); + free(ROM_buffer); + (*CoreShutdown)(); + DetachCoreLib(); + return 10; + } + free(ROM_buffer); /* the core copies the ROM image, so we can release this buffer immediately */ + + /* handle the cheat codes */ + CheatStart(l_CheatMode, l_CheatNumList); + if (l_CheatMode == CHEAT_SHOW_LIST) + { + (*CoreDoCommand)(M64CMD_ROM_CLOSE, 0, NULL); + (*CoreShutdown)(); + DetachCoreLib(); + return 11; + } + + /* search for and load plugins */ + rval = PluginSearchLoad(l_ConfigUI); + if (rval != M64ERR_SUCCESS) + { + (*CoreDoCommand)(M64CMD_ROM_CLOSE, 0, NULL); + (*CoreShutdown)(); + DetachCoreLib(); + return 12; + } + + /* attach plugins to core */ + for (i = 0; i < 4; i++) + { + if ((*CoreAttachPlugin)(g_PluginMap[i].type, g_PluginMap[i].handle) != M64ERR_SUCCESS) + { + DebugMessage(M64MSG_ERROR, "core error while attaching %s plugin.", g_PluginMap[i].name); + (*CoreDoCommand)(M64CMD_ROM_CLOSE, 0, NULL); + (*CoreShutdown)(); + DetachCoreLib(); + return 13; + } + } + + /* set up Frame Callback if --testshots is enabled */ + if (l_TestShotList != NULL) + { + if ((*CoreDoCommand)(M64CMD_SET_FRAME_CALLBACK, 0, FrameCallback) != M64ERR_SUCCESS) + { + DebugMessage(M64MSG_WARNING, "couldn't set frame callback, so --testshots won't work."); + } + } + + /* run the game */ + #ifdef PAULSCODE + // paulscode: workaround for broken M64CMD_RESET. Set do_Start = 1 before M64CMD_STOP to reset the emulator. + while( do_Start ) + { + do_Start = 0; + (*CoreDoCommand)(M64CMD_EXECUTE, 0, NULL); + } + #else + (*CoreDoCommand)(M64CMD_EXECUTE, 0, NULL); + #endif + + /* detach plugins from core and unload them */ + for (i = 0; i < 4; i++) + (*CoreDetachPlugin)(g_PluginMap[i].type); + PluginUnload(); + + /* close the ROM image */ + (*CoreDoCommand)(M64CMD_ROM_CLOSE, 0, NULL); + + /* save the configuration file again if --nosaveoptions was not specified, to keep any updated parameters from the core/plugins */ + if (l_SaveOptions) + SaveConfigurationOptions(); + + /* Shut down and release the Core library */ + (*CoreShutdown)(); + DetachCoreLib(); + + /* free allocated memory */ + if (l_TestShotList != NULL) + free(l_TestShotList); + + return 0; +} +