Added missing launcher
[mupen64plus-pandora.git] / source / front-end / src / main.c
CommitLineData
5288f542 1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Mupen64plus-ui-console - main.c *
3 * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
4 * Copyright (C) 2007-2010 Richard42 *
5 * Copyright (C) 2008 Ebenblues Nmn Okaygo Tillin9 *
6 * Copyright (C) 2002 Hacktarux *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the *
20 * Free Software Foundation, Inc., *
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
22 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
23
24/* This is the main application entry point for the console-only front-end
25 * for Mupen64Plus v2.0.
26 */
27
28#include <stdio.h>
29#include <string.h>
30#include <stdlib.h>
31#include <stdarg.h>
32
33#include <SDL_main.h>
34
35#include "cheat.h"
36#include "main.h"
37#include "plugin.h"
38#include "version.h"
39#include "core_interface.h"
40#include "compare_core.h"
41#include "osal_preproc.h"
42
43#ifdef PAULSCODE
44//#include "ae_bridge.h"
45#endif
46
47/* Version number for UI-Console config section parameters */
48#define CONFIG_PARAM_VERSION 1.00
49
50/** global variables **/
51int g_Verbose = 0;
52
53/** static (local) variables **/
54static m64p_handle l_ConfigCore = NULL;
55static m64p_handle l_ConfigVideo = NULL;
56static m64p_handle l_ConfigUI = NULL;
57
58static const char *l_CoreLibPath = NULL;
59static const char *l_ConfigDirPath = NULL;
60static const char *l_ROMFilepath = NULL; // filepath of ROM to load & run at startup
61
62#if defined(SHAREDIR)
63 static const char *l_DataDirPath = SHAREDIR;
64#else
65 static const char *l_DataDirPath = NULL;
66#endif
67
68static int *l_TestShotList = NULL; // list of screenshots to take for regression test support
69static int l_TestShotIdx = 0; // index of next screenshot frame in list
70static int l_SaveOptions = 1; // save command-line options in configuration file (enabled by default)
71static int l_CoreCompareMode = 0; // 0 = disable, 1 = send, 2 = receive
72
73static eCheatMode l_CheatMode = CHEAT_DISABLE;
74static char *l_CheatNumList = NULL;
75
76/*********************************************************************************************************
77 * Callback functions from the core
78 */
79
80void DebugMessage(int level, const char *message, ...)
81{
82 char msgbuf[1024];
83 va_list args;
84
85 va_start(args, message);
86 vsnprintf(msgbuf, 1024, message, args);
87
88 DebugCallback("UI-Console", level, msgbuf);
89
90 va_end(args);
91}
92
93void DebugCallback(void *Context, int level, const char *message)
94{
95#ifdef ANDROID0
96 if (level == M64MSG_ERROR)
97 __android_log_print(ANDROID_LOG_ERROR, (const char *) Context, "%s", message);
98 else if (level == M64MSG_WARNING)
99 __android_log_print(ANDROID_LOG_WARN, (const char *) Context, "%s", message);
100 else if (level == M64MSG_INFO)
101 __android_log_print(ANDROID_LOG_INFO, (const char *) Context, "%s", message);
102 else if (level == M64MSG_STATUS)
103 __android_log_print(ANDROID_LOG_DEBUG, (const char *) Context, "%s", message);
104 else if (level == M64MSG_VERBOSE)
105 {
106 if (g_Verbose)
107 __android_log_print(ANDROID_LOG_VERBOSE, (const char *) Context, "%s", message);
108 }
109 else
110 __android_log_print(ANDROID_LOG_ERROR, (const char *) Context, "Unknown: %s", message);
111#else
112 if (level == M64MSG_ERROR)
113 printf("%s Error: %s\n", (const char *) Context, message);
114 else if (level == M64MSG_WARNING)
115 printf("%s Warning: %s\n", (const char *) Context, message);
116 else if (level == M64MSG_INFO)
117 printf("%s: %s\n", (const char *) Context, message);
118 else if (level == M64MSG_STATUS)
119 printf("%s Status: %s\n", (const char *) Context, message);
120 else if (level == M64MSG_VERBOSE)
121 {
122 if (g_Verbose)
123 printf("%s: %s\n", (const char *) Context, message);
124 }
125 else
126 printf("%s Unknown: %s\n", (const char *) Context, message);
127#endif
128}
129
130static void FrameCallback(unsigned int FrameIndex)
131{
132 // take a screenshot if we need to
133 if (l_TestShotList != NULL)
134 {
135 int nextshot = l_TestShotList[l_TestShotIdx];
136 if (nextshot == FrameIndex)
137 {
138 (*CoreDoCommand)(M64CMD_TAKE_NEXT_SCREENSHOT, 0, NULL); /* tell the core take a screenshot */
139 // advance list index to next screenshot frame number. If it's 0, then quit
140 l_TestShotIdx++;
141 }
142 else if (nextshot == 0)
143 {
144 (*CoreDoCommand)(M64CMD_STOP, 0, NULL); /* tell the core to shut down ASAP */
145 free(l_TestShotList);
146 l_TestShotList = NULL;
147 }
148 }
149}
150
151#ifdef PAULSCODE
152void StateCallback( void *Context, m64p_core_param ParamChanged, int NewValue )
153{
154 /*----ParamChanged-----------------
155 * --------NewValue--------
156 * M64CORE_EMU_STATE 1
157 * M64EMU_STOPPED 1
158 * M64EMU_RUNNING 2
159 * M64EMU_PAUSED 3
160 * M64CORE_VIDEO_MODE 2
161 * M64CORE_SAVESTATE_SLOT 3
162 * M64CORE_SPEED_FACTOR 4
163 * M64CORE_SPEED_LIMITER 5
164 * M64CORE_VIDEO_SIZE 6
165 * M64CORE_AUDIO_VOLUME 7
166 * M64CORE_AUDIO_MUTE 8
167 * M64CORE_INPUT_GAMESHARK 9
168 * M64CORE_STATE_LOADCOMPLETE 10
169 * (successful) 1
170 * (unsuccessful) 0
171 * M64CORE_STATE_SAVECOMPLETE 11
172 * (successful) 1
173 * (unsuccessful) 0
174 */
175
176 if( ParamChanged == M64CORE_EMU_STATE || ParamChanged == M64CORE_STATE_SAVECOMPLETE || ParamChanged == M64CORE_STATE_LOADCOMPLETE )
177 Android_JNI_State_Callback( ParamChanged, NewValue );
178}
179#endif
180
181/*********************************************************************************************************
182 * Configuration handling
183 */
184
185static m64p_error OpenConfigurationHandles(void)
186{
187 float fConfigParamsVersion;
188 int bSaveConfig = 0;
189 m64p_error rval;
190
191 /* Open Configuration sections for core library and console User Interface */
192 rval = (*ConfigOpenSection)("Core", &l_ConfigCore);
193 if (rval != M64ERR_SUCCESS)
194 {
195 DebugMessage(M64MSG_ERROR, "failed to open 'Core' configuration section");
196 return rval;
197 }
198
199 rval = (*ConfigOpenSection)("Video-General", &l_ConfigVideo);
200 if (rval != M64ERR_SUCCESS)
201 {
202 DebugMessage(M64MSG_ERROR, "failed to open 'Video-General' configuration section");
203 return rval;
204 }
205
206 rval = (*ConfigOpenSection)("UI-Console", &l_ConfigUI);
207 if (rval != M64ERR_SUCCESS)
208 {
209 DebugMessage(M64MSG_ERROR, "failed to open 'UI-Console' configuration section");
210 return rval;
211 }
212
213 if ((*ConfigGetParameter)(l_ConfigUI, "Version", M64TYPE_FLOAT, &fConfigParamsVersion, sizeof(float)) != M64ERR_SUCCESS)
214 {
215 DebugMessage(M64MSG_WARNING, "No version number in 'UI-Console' config section. Setting defaults.");
216 (*ConfigDeleteSection)("UI-Console");
217 (*ConfigOpenSection)("UI-Console", &l_ConfigUI);
218 bSaveConfig = 1;
219 }
220 else if (((int) fConfigParamsVersion) != ((int) CONFIG_PARAM_VERSION))
221 {
222 DebugMessage(M64MSG_WARNING, "Incompatible version %.2f in 'UI-Console' config section: current is %.2f. Setting defaults.", fConfigParamsVersion, (float) CONFIG_PARAM_VERSION);
223 (*ConfigDeleteSection)("UI-Console");
224 (*ConfigOpenSection)("UI-Console", &l_ConfigUI);
225 bSaveConfig = 1;
226 }
227 else if ((CONFIG_PARAM_VERSION - fConfigParamsVersion) >= 0.0001f)
228 {
229 /* handle upgrades */
230 float fVersion = CONFIG_PARAM_VERSION;
231 ConfigSetParameter(l_ConfigUI, "Version", M64TYPE_FLOAT, &fVersion);
232 DebugMessage(M64MSG_INFO, "Updating parameter set version in 'UI-Console' config section to %.2f", fVersion);
233 bSaveConfig = 1;
234 }
235
236 /* Set default values for my Config parameters */
237 (*ConfigSetDefaultFloat)(l_ConfigUI, "Version", CONFIG_PARAM_VERSION, "Mupen64Plus UI-Console config parameter set version number. Please don't change this version number.");
238 (*ConfigSetDefaultString)(l_ConfigUI, "PluginDir", OSAL_CURRENT_DIR, "Directory in which to search for plugins");
239 (*ConfigSetDefaultString)(l_ConfigUI, "VideoPlugin", "mupen64plus-video-rice" OSAL_DLL_EXTENSION, "Filename of video plugin");
240 (*ConfigSetDefaultString)(l_ConfigUI, "AudioPlugin", "mupen64plus-audio-sdl" OSAL_DLL_EXTENSION, "Filename of audio plugin");
241 (*ConfigSetDefaultString)(l_ConfigUI, "InputPlugin", "mupen64plus-input-sdl" OSAL_DLL_EXTENSION, "Filename of input plugin");
242 (*ConfigSetDefaultString)(l_ConfigUI, "RspPlugin", "mupen64plus-rsp-hle" OSAL_DLL_EXTENSION, "Filename of RSP plugin");
243
244 if (bSaveConfig && ConfigSaveSection != NULL) /* ConfigSaveSection was added in Config API v2.1.0 */
245 (*ConfigSaveSection)("UI-Console");
246
247 return M64ERR_SUCCESS;
248}
249
250static m64p_error SaveConfigurationOptions(void)
251{
252 /* if shared data directory was given on the command line, write it into the config file */
253 if (l_DataDirPath != NULL)
254 (*ConfigSetParameter)(l_ConfigCore, "SharedDataPath", M64TYPE_STRING, l_DataDirPath);
255
256 /* if any plugin filepaths were given on the command line, write them into the config file */
257 if (g_PluginDir != NULL)
258 (*ConfigSetParameter)(l_ConfigUI, "PluginDir", M64TYPE_STRING, g_PluginDir);
259 if (g_GfxPlugin != NULL)
260 (*ConfigSetParameter)(l_ConfigUI, "VideoPlugin", M64TYPE_STRING, g_GfxPlugin);
261 if (g_AudioPlugin != NULL)
262 (*ConfigSetParameter)(l_ConfigUI, "AudioPlugin", M64TYPE_STRING, g_AudioPlugin);
263 if (g_InputPlugin != NULL)
264 (*ConfigSetParameter)(l_ConfigUI, "InputPlugin", M64TYPE_STRING, g_InputPlugin);
265 if (g_RspPlugin != NULL)
266 (*ConfigSetParameter)(l_ConfigUI, "RspPlugin", M64TYPE_STRING, g_RspPlugin);
267
268 return (*ConfigSaveFile)();
269}
270
271/*********************************************************************************************************
272 * Command-line parsing
273 */
274
275static void printUsage(const char *progname)
276{
277 printf("Usage: %s [parameters] [romfile]\n"
278 "\n"
279 "Parameters:\n"
280 " --noosd : disable onscreen display\n"
281 " --osd : enable onscreen display\n"
282 " --fullscreen : use fullscreen display mode\n"
283 " --windowed : use windowed display mode\n"
284 " --resolution (res) : display resolution (640x480, 800x600, 1024x768, etc)\n"
285 " --nospeedlimit : disable core speed limiter (should be used with dummy audio plugin)\n"
286 " --cheats (cheat-spec) : enable or list cheat codes for the given rom file\n"
287 " --corelib (filepath) : use core library (filepath) (can be only filename or full path)\n"
288 " --configdir (dir) : force configation directory to (dir); should contain mupen64plus.cfg\n"
289 " --datadir (dir) : search for shared data files (.ini files, languages, etc) in (dir)\n"
290 " --plugindir (dir) : search for plugins in (dir)\n"
291 " --sshotdir (dir) : set screenshot directory to (dir)\n"
292 " --gfx (plugin-spec) : use gfx plugin given by (plugin-spec)\n"
293 " --audio (plugin-spec) : use audio plugin given by (plugin-spec)\n"
294 " --input (plugin-spec) : use input plugin given by (plugin-spec)\n"
295 " --rsp (plugin-spec) : use rsp plugin given by (plugin-spec)\n"
296 " --emumode (mode) : set emu mode to: 0=Pure Interpreter 1=Interpreter 2=DynaRec\n"
297 " --testshots (list) : take screenshots at frames given in comma-separated (list), then quit\n"
298 " --set (param-spec) : set a configuration variable, format: ParamSection[ParamName]=Value\n"
299 " --core-compare-send : use the Core Comparison debugging feature, in data sending mode\n"
300 " --core-compare-recv : use the Core Comparison debugging feature, in data receiving mode\n"
301 " --nosaveoptions : do not save the given command-line options in configuration file\n"
302 " --verbose : print lots of information\n"
303 " --help : see this help message\n\n"
304 "(plugin-spec):\n"
305 " (pluginname) : filename (without path) of plugin to find in plugin directory\n"
306 " (pluginpath) : full path and filename of plugin\n"
307 " 'dummy' : use dummy plugin\n\n"
308 "(cheat-spec):\n"
309 " 'list' : show all of the available cheat codes\n"
310 " 'all' : enable all of the available cheat codes\n"
311 " (codelist) : a comma-separated list of cheat code numbers to enable,\n"
312 " with dashes to use code variables (ex 1-2 to use cheat 1 option 2)\n"
313 "\n", progname);
314
315 return;
316}
317
318static int SetConfigParameter(const char *ParamSpec)
319{
320 char *ParsedString, *VarName, *VarValue=NULL;
321 m64p_handle ConfigSection;
322 m64p_type VarType;
323 m64p_error rval;
324
325 if (ParamSpec == NULL)
326 {
327 DebugMessage(M64MSG_ERROR, "ParamSpec is NULL in SetConfigParameter()");
328 return 1;
329 }
330
331 /* make a copy of the input string */
332 ParsedString = (char *) malloc(strlen(ParamSpec) + 1);
333 if (ParsedString == NULL)
334 {
335 DebugMessage(M64MSG_ERROR, "SetConfigParameter() couldn't allocate memory for temporary string.");
336 return 2;
337 }
338 strcpy(ParsedString, ParamSpec);
339
340 /* parse it for the simple section[name]=value format */
341 VarName = strchr(ParsedString, '[');
342 if (VarName != NULL)
343 {
344 *VarName++ = 0;
345 VarValue = strchr(VarName, ']');
346 if (VarValue != NULL)
347 {
348 *VarValue++ = 0;
349 }
350 }
351 if (VarName == NULL || VarValue == NULL || *VarValue != '=')
352 {
353 DebugMessage(M64MSG_ERROR, "invalid (param-spec) '%s'", ParamSpec);
354 free(ParsedString);
355 return 3;
356 }
357 VarValue++;
358
359 /* then set the value */
360 rval = (*ConfigOpenSection)(ParsedString, &ConfigSection);
361 if (rval != M64ERR_SUCCESS)
362 {
363 DebugMessage(M64MSG_ERROR, "SetConfigParameter failed to open config section '%s'", ParsedString);
364 free(ParsedString);
365 return 4;
366 }
367 if ((*ConfigGetParameterType)(ConfigSection, VarName, &VarType) == M64ERR_SUCCESS)
368 {
369 switch(VarType)
370 {
371 int ValueInt;
372 float ValueFloat;
373 case M64TYPE_INT:
374 ValueInt = atoi(VarValue);
375 ConfigSetParameter(ConfigSection, VarName, M64TYPE_INT, &ValueInt);
376 break;
377 case M64TYPE_FLOAT:
378 ValueFloat = (float) atof(VarValue);
379 ConfigSetParameter(ConfigSection, VarName, M64TYPE_FLOAT, &ValueFloat);
380 break;
381 case M64TYPE_BOOL:
382 ValueInt = (int) (osal_insensitive_strcmp(VarValue, "true") == 0);
383 ConfigSetParameter(ConfigSection, VarName, M64TYPE_BOOL, &ValueInt);
384 break;
385 case M64TYPE_STRING:
386 ConfigSetParameter(ConfigSection, VarName, M64TYPE_STRING, VarValue);
387 break;
388 default:
389 DebugMessage(M64MSG_ERROR, "invalid VarType in SetConfigParameter()");
390 return 5;
391 }
392 }
393 else
394 {
395 ConfigSetParameter(ConfigSection, VarName, M64TYPE_STRING, VarValue);
396 }
397
398 free(ParsedString);
399 return 0;
400}
401
402static int *ParseNumberList(const char *InputString, int *ValuesFound)
403{
404 const char *str;
405 int *OutputList;
406
407 /* count the number of integers in the list */
408 int values = 1;
409 str = InputString;
410 while ((str = strchr(str, ',')) != NULL)
411 {
412 str++;
413 values++;
414 }
415
416 /* create a list and populate it with the frame counter values at which to take screenshots */
417 if ((OutputList = (int *) malloc(sizeof(int) * (values + 1))) != NULL)
418 {
419 int idx = 0;
420 str = InputString;
421 while (str != NULL)
422 {
423 OutputList[idx++] = atoi(str);
424 str = strchr(str, ',');
425 if (str != NULL) str++;
426 }
427 OutputList[idx] = 0;
428 }
429
430 if (ValuesFound != NULL)
431 *ValuesFound = values;
432 return OutputList;
433}
434
435static int ParseCommandLineInitial(int argc, const char **argv)
436{
437 int i;
438
439 /* look through commandline options */
440 for (i = 1; i < argc; i++)
441 {
442 int ArgsLeft = argc - i - 1;
443
444 if (strcmp(argv[i], "--corelib") == 0 && ArgsLeft >= 1)
445 {
446 l_CoreLibPath = argv[i+1];
447 i++;
448 }
449 else if (strcmp(argv[i], "--configdir") == 0 && ArgsLeft >= 1)
450 {
451 l_ConfigDirPath = argv[i+1];
452 i++;
453 }
454 else if (strcmp(argv[i], "--datadir") == 0 && ArgsLeft >= 1)
455 {
456 l_DataDirPath = argv[i+1];
457 i++;
458 }
459 else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0)
460 {
461 printUsage(argv[0]);
462 return 1;
463 }
464 }
465
466 return 0;
467}
468
469static m64p_error ParseCommandLineFinal(int argc, const char **argv)
470{
471 int i;
472
473 /* parse commandline options */
474 for (i = 1; i < argc; i++)
475 {
476 int ArgsLeft = argc - i - 1;
477 if (strcmp(argv[i], "--noosd") == 0)
478 {
479 int Osd = 0;
480 (*ConfigSetParameter)(l_ConfigCore, "OnScreenDisplay", M64TYPE_BOOL, &Osd);
481 }
482 else if (strcmp(argv[i], "--osd") == 0)
483 {
484 int Osd = 1;
485 (*ConfigSetParameter)(l_ConfigCore, "OnScreenDisplay", M64TYPE_BOOL, &Osd);
486 }
487 else if (strcmp(argv[i], "--fullscreen") == 0)
488 {
489 int Fullscreen = 1;
490 (*ConfigSetParameter)(l_ConfigVideo, "Fullscreen", M64TYPE_BOOL, &Fullscreen);
491 }
492 else if (strcmp(argv[i], "--windowed") == 0)
493 {
494 int Fullscreen = 0;
495 (*ConfigSetParameter)(l_ConfigVideo, "Fullscreen", M64TYPE_BOOL, &Fullscreen);
496 }
497 else if (strcmp(argv[i], "--nospeedlimit") == 0)
498 {
499 int EnableSpeedLimit = 0;
500 if (g_CoreAPIVersion < 0x020001)
501 DebugMessage(M64MSG_WARNING, "core library doesn't support --nospeedlimit");
502 else
503 {
504 if ((*CoreDoCommand)(M64CMD_CORE_STATE_SET, M64CORE_SPEED_LIMITER, &EnableSpeedLimit) != M64ERR_SUCCESS)
505 DebugMessage(M64MSG_ERROR, "core gave error while setting --nospeedlimit option");
506 }
507 }
508 else if ((strcmp(argv[i], "--corelib") == 0 || strcmp(argv[i], "--configdir") == 0 ||
509 strcmp(argv[i], "--datadir") == 0) && ArgsLeft >= 1)
510 { /* these are handled in ParseCommandLineInitial */
511 i++;
512 }
513 else if (strcmp(argv[i], "--resolution") == 0 && ArgsLeft >= 1)
514 {
515 const char *res = argv[i+1];
516 int xres, yres;
517 i++;
518 if (sscanf(res, "%ix%i", &xres, &yres) != 2)
519 DebugMessage(M64MSG_WARNING, "couldn't parse resolution '%s'", res);
520 else
521 {
522 (*ConfigSetParameter)(l_ConfigVideo, "ScreenWidth", M64TYPE_INT, &xres);
523 (*ConfigSetParameter)(l_ConfigVideo, "ScreenHeight", M64TYPE_INT, &yres);
524 }
525 }
526 else if (strcmp(argv[i], "--cheats") == 0 && ArgsLeft >= 1)
527 {
528 if (strcmp(argv[i+1], "all") == 0)
529 l_CheatMode = CHEAT_ALL;
530 else if (strcmp(argv[i+1], "list") == 0)
531 l_CheatMode = CHEAT_SHOW_LIST;
532 else
533 {
534 l_CheatMode = CHEAT_LIST;
535 l_CheatNumList = (char*) argv[i+1];
536 }
537 i++;
538 }
539 else if (strcmp(argv[i], "--plugindir") == 0 && ArgsLeft >= 1)
540 {
541 g_PluginDir = argv[i+1];
542 i++;
543 }
544 else if (strcmp(argv[i], "--sshotdir") == 0 && ArgsLeft >= 1)
545 {
546 (*ConfigSetParameter)(l_ConfigCore, "ScreenshotPath", M64TYPE_STRING, argv[i+1]);
547 i++;
548 }
549 else if (strcmp(argv[i], "--gfx") == 0 && ArgsLeft >= 1)
550 {
551 g_GfxPlugin = argv[i+1];
552 i++;
553 }
554 else if (strcmp(argv[i], "--audio") == 0 && ArgsLeft >= 1)
555 {
556 g_AudioPlugin = argv[i+1];
557 i++;
558 }
559 else if (strcmp(argv[i], "--input") == 0 && ArgsLeft >= 1)
560 {
561 g_InputPlugin = argv[i+1];
562 i++;
563 }
564 else if (strcmp(argv[i], "--rsp") == 0 && ArgsLeft >= 1)
565 {
566 g_RspPlugin = argv[i+1];
567 i++;
568 }
569 else if (strcmp(argv[i], "--emumode") == 0 && ArgsLeft >= 1)
570 {
571 int emumode = atoi(argv[i+1]);
572 i++;
573 if (emumode < 0 || emumode > 2)
574 {
575 DebugMessage(M64MSG_WARNING, "invalid --emumode value '%i'", emumode);
576 continue;
577 }
578 if (emumode == 2 && !(g_CoreCapabilities & M64CAPS_DYNAREC))
579 {
580 DebugMessage(M64MSG_WARNING, "Emulator core doesn't support Dynamic Recompiler.");
581 emumode = 1;
582 }
583 (*ConfigSetParameter)(l_ConfigCore, "R4300Emulator", M64TYPE_INT, &emumode);
584 }
585 else if (strcmp(argv[i], "--testshots") == 0 && ArgsLeft >= 1)
586 {
587 l_TestShotList = ParseNumberList(argv[i+1], NULL);
588 i++;
589 }
590 else if (strcmp(argv[i], "--set") == 0 && ArgsLeft >= 1)
591 {
592 if (SetConfigParameter(argv[i+1]) != 0)
593 return M64ERR_INPUT_INVALID;
594 i++;
595 }
596 else if (strcmp(argv[i], "--core-compare-send") == 0)
597 {
598 l_CoreCompareMode = 1;
599 }
600 else if (strcmp(argv[i], "--core-compare-recv") == 0)
601 {
602 l_CoreCompareMode = 2;
603 }
604 else if (strcmp(argv[i], "--nosaveoptions") == 0)
605 {
606 l_SaveOptions = 0;
607 }
608 else if (ArgsLeft == 0)
609 {
610 /* this is the last arg, it should be a ROM filename */
611 l_ROMFilepath = argv[i];
612 return M64ERR_SUCCESS;
613 }
614 else if (strcmp(argv[i], "--verbose") == 0)
615 {
616 g_Verbose = 1;
617 }
618 else
619 {
620 DebugMessage(M64MSG_WARNING, "unrecognized command-line parameter '%s'", argv[i]);
621 }
622 /* continue argv loop */
623 }
624
625 /* missing ROM filepath */
626 DebugMessage(M64MSG_ERROR, "no ROM filepath given");
627 return M64ERR_INPUT_INVALID;
628}
629
630/*********************************************************************************************************
631* main function
632*/
633int main(int argc, char *argv[])
634{
635 int i;
636
637 printf(" __ __ __ _ _ ____ _ \n");
638 printf("| \\/ |_ _ _ __ ___ _ __ / /_ | || | | _ \\| |_ _ ___ \n");
639 printf("| |\\/| | | | | '_ \\ / _ \\ '_ \\| '_ \\| || |_| |_) | | | | / __| \n");
640 printf("| | | | |_| | |_) | __/ | | | (_) |__ _| __/| | |_| \\__ \\ \n");
641 printf("|_| |_|\\__,_| .__/ \\___|_| |_|\\___/ |_| |_| |_|\\__,_|___/ \n");
642 printf(" |_| http://code.google.com/p/mupen64plus/ \n");
643 printf("%s Version %i.%i.%i\n\n", CONSOLE_UI_NAME, VERSION_PRINTF_SPLIT(CONSOLE_UI_VERSION));
644
645 /* bootstrap some special parameters from the command line */
646 if (ParseCommandLineInitial(argc, (const char **) argv) != 0)
647 return 1;
648
649 /* load the Mupen64Plus core library */
650 if (AttachCoreLib(l_CoreLibPath) != M64ERR_SUCCESS)
651 return 2;
652
653 /* start the Mupen64Plus core library, load the configuration file */
654 #ifdef PAULSCODE
655 m64p_error rval = (*CoreStartup)( CORE_API_VERSION, l_ConfigDirPath, l_DataDirPath, "Core", DebugCallback, NULL, StateCallback );
656 #else
657 m64p_error rval = (*CoreStartup)(CORE_API_VERSION, l_ConfigDirPath, l_DataDirPath, "Core", DebugCallback, NULL, NULL);
658 #endif
659 if (rval != M64ERR_SUCCESS)
660 {
661 DebugMessage(M64MSG_ERROR, "couldn't start Mupen64Plus core library.");
662 DetachCoreLib();
663 return 3;
664 }
665
666 /* Open configuration sections */
667 rval = OpenConfigurationHandles();
668 if (rval != M64ERR_SUCCESS)
669 {
670 (*CoreShutdown)();
671 DetachCoreLib();
672 return 4;
673 }
674
675 /* parse command-line options */
676 rval = ParseCommandLineFinal(argc, (const char **) argv);
677 if (rval != M64ERR_SUCCESS)
678 {
679 (*CoreShutdown)();
680 DetachCoreLib();
681 return 5;
682 }
683
684 /* Handle the core comparison feature */
685 if (l_CoreCompareMode != 0 && !(g_CoreCapabilities & M64CAPS_CORE_COMPARE))
686 {
687 DebugMessage(M64MSG_ERROR, "can't use --core-compare feature with this Mupen64Plus core library.");
688 DetachCoreLib();
689 return 6;
690 }
691 compare_core_init(l_CoreCompareMode);
692
693 /* save the given command-line options in configuration file if requested */
694 if (l_SaveOptions)
695 SaveConfigurationOptions();
696
697 /* load ROM image */
698 FILE *fPtr = fopen(l_ROMFilepath, "rb");
699 if (fPtr == NULL)
700 {
701 DebugMessage(M64MSG_ERROR, "couldn't open ROM file '%s' for reading.", l_ROMFilepath);
702 (*CoreShutdown)();
703 DetachCoreLib();
704 return 7;
705 }
706
707 /* get the length of the ROM, allocate memory buffer, load it from disk */
708 long romlength = 0;
709 fseek(fPtr, 0L, SEEK_END);
710 romlength = ftell(fPtr);
711 fseek(fPtr, 0L, SEEK_SET);
712 unsigned char *ROM_buffer = (unsigned char *) malloc(romlength);
713 if (ROM_buffer == NULL)
714 {
715 DebugMessage(M64MSG_ERROR, "couldn't allocate %li-byte buffer for ROM image file '%s'.", romlength, l_ROMFilepath);
716 fclose(fPtr);
717 (*CoreShutdown)();
718 DetachCoreLib();
719 return 8;
720 }
721 else if (fread(ROM_buffer, 1, romlength, fPtr) != romlength)
722 {
723 DebugMessage(M64MSG_ERROR, "couldn't read %li bytes from ROM image file '%s'.", romlength, l_ROMFilepath);
724 free(ROM_buffer);
725 fclose(fPtr);
726 (*CoreShutdown)();
727 DetachCoreLib();
728 return 9;
729 }
730 fclose(fPtr);
731
732 /* Try to load the ROM image into the core */
733 if ((*CoreDoCommand)(M64CMD_ROM_OPEN, (int) romlength, ROM_buffer) != M64ERR_SUCCESS)
734 {
735 DebugMessage(M64MSG_ERROR, "core failed to open ROM image file '%s'.", l_ROMFilepath);
736 free(ROM_buffer);
737 (*CoreShutdown)();
738 DetachCoreLib();
739 return 10;
740 }
741 free(ROM_buffer); /* the core copies the ROM image, so we can release this buffer immediately */
742
743 /* handle the cheat codes */
744 CheatStart(l_CheatMode, l_CheatNumList);
745 if (l_CheatMode == CHEAT_SHOW_LIST)
746 {
747 (*CoreDoCommand)(M64CMD_ROM_CLOSE, 0, NULL);
748 (*CoreShutdown)();
749 DetachCoreLib();
750 return 11;
751 }
752
753 /* search for and load plugins */
754 rval = PluginSearchLoad(l_ConfigUI);
755 if (rval != M64ERR_SUCCESS)
756 {
757 (*CoreDoCommand)(M64CMD_ROM_CLOSE, 0, NULL);
758 (*CoreShutdown)();
759 DetachCoreLib();
760 return 12;
761 }
762
763 /* attach plugins to core */
764 for (i = 0; i < 4; i++)
765 {
766 if ((*CoreAttachPlugin)(g_PluginMap[i].type, g_PluginMap[i].handle) != M64ERR_SUCCESS)
767 {
768 DebugMessage(M64MSG_ERROR, "core error while attaching %s plugin.", g_PluginMap[i].name);
769 (*CoreDoCommand)(M64CMD_ROM_CLOSE, 0, NULL);
770 (*CoreShutdown)();
771 DetachCoreLib();
772 return 13;
773 }
774 }
775
776 /* set up Frame Callback if --testshots is enabled */
777 if (l_TestShotList != NULL)
778 {
779 if ((*CoreDoCommand)(M64CMD_SET_FRAME_CALLBACK, 0, FrameCallback) != M64ERR_SUCCESS)
780 {
781 DebugMessage(M64MSG_WARNING, "couldn't set frame callback, so --testshots won't work.");
782 }
783 }
784
785 /* run the game */
786 #ifdef PAULSCODE
787 // paulscode: workaround for broken M64CMD_RESET. Set do_Start = 1 before M64CMD_STOP to reset the emulator.
788 while( do_Start )
789 {
790 do_Start = 0;
791 (*CoreDoCommand)(M64CMD_EXECUTE, 0, NULL);
792 }
793 #else
794 (*CoreDoCommand)(M64CMD_EXECUTE, 0, NULL);
795 #endif
796
797 /* detach plugins from core and unload them */
798 for (i = 0; i < 4; i++)
799 (*CoreDetachPlugin)(g_PluginMap[i].type);
800 PluginUnload();
801
802 /* close the ROM image */
803 (*CoreDoCommand)(M64CMD_ROM_CLOSE, 0, NULL);
804
805 /* save the configuration file again if --nosaveoptions was not specified, to keep any updated parameters from the core/plugins */
806 if (l_SaveOptions)
807 SaveConfigurationOptions();
808
809 /* Shut down and release the Core library */
810 (*CoreShutdown)();
811 DetachCoreLib();
812
813 /* free allocated memory */
814 if (l_TestShotList != NULL)
815 free(l_TestShotList);
816
817 return 0;
818}
819