PageRenderTime 53ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/src/main.c

https://bitbucket.org/casualjames/mupen64plus-ui-console-pifboot
C | 745 lines | 593 code | 73 blank | 79 comment | 231 complexity | d1ff1c98a3debe57d9e5a8bfb43c5bee MD5 | raw file
Possible License(s): GPL-2.0
  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. /* This is the main application entry point for the console-only front-end
  24. * for Mupen64Plus v2.0.
  25. */
  26. #include <stdio.h>
  27. #include <string.h>
  28. #include <stdlib.h>
  29. // The mac version of SDL requires inclusion of SDL_main in the executable
  30. #ifdef __APPLE__
  31. #include <SDL/SDL_main.h>
  32. #endif
  33. #include "cheat.h"
  34. #include "main.h"
  35. #include "plugin.h"
  36. #include "version.h"
  37. #include "core_interface.h"
  38. #include "compare_core.h"
  39. #include "osal_preproc.h"
  40. /** global variables **/
  41. int g_Verbose = 0;
  42. /** static (local) variables **/
  43. static m64p_handle l_ConfigCore = NULL;
  44. static m64p_handle l_ConfigVideo = NULL;
  45. static m64p_handle l_ConfigUI = NULL;
  46. static const char *l_CoreLibPath = NULL;
  47. static const char *l_ConfigDirPath = NULL;
  48. static const char *l_ROMFilepath = NULL; // filepath of ROM to load & run at startup
  49. #if defined(SHAREDIR)
  50. static const char *l_DataDirPath = SHAREDIR;
  51. #else
  52. static const char *l_DataDirPath = NULL;
  53. #endif
  54. static int *l_TestShotList = NULL; // list of screenshots to take for regression test support
  55. static int l_TestShotIdx = 0; // index of next screenshot frame in list
  56. static int l_SaveOptions = 0; // save command-line options in configuration file
  57. static int l_CoreCompareMode = 0; // 0 = disable, 1 = send, 2 = receive
  58. static eCheatMode l_CheatMode = CHEAT_DISABLE;
  59. static char *l_CheatNumList = NULL;
  60. static const char *l_PifRomPath = NULL;
  61. /*********************************************************************************************************
  62. * Callback functions from the core
  63. */
  64. void DebugCallback(void *Context, int level, const char *message)
  65. {
  66. if (level <= 1)
  67. printf("%s Error: %s\n", (const char *) Context, message);
  68. else if (level == 2)
  69. printf("%s Warning: %s\n", (const char *) Context, message);
  70. else if (level == 3 || (level == 5 && g_Verbose))
  71. printf("%s: %s\n", (const char *) Context, message);
  72. else if (level == 4)
  73. printf("%s Status: %s\n", (const char *) Context, message);
  74. /* ignore the verbose info for now */
  75. }
  76. static void FrameCallback(unsigned int FrameIndex)
  77. {
  78. // take a screenshot if we need to
  79. if (l_TestShotList != NULL)
  80. {
  81. int nextshot = l_TestShotList[l_TestShotIdx];
  82. if (nextshot == FrameIndex)
  83. {
  84. (*CoreDoCommand)(M64CMD_TAKE_NEXT_SCREENSHOT, 0, NULL); /* tell the core take a screenshot */
  85. // advance list index to next screenshot frame number. If it's 0, then quit
  86. l_TestShotIdx++;
  87. }
  88. else if (nextshot == 0)
  89. {
  90. (*CoreDoCommand)(M64CMD_STOP, 0, NULL); /* tell the core to shut down ASAP */
  91. free(l_TestShotList);
  92. l_TestShotList = NULL;
  93. }
  94. }
  95. }
  96. /*********************************************************************************************************
  97. * Configuration handling
  98. */
  99. static m64p_error OpenConfigurationHandles(void)
  100. {
  101. m64p_error rval;
  102. /* Open Configuration sections for core library and console User Interface */
  103. rval = (*ConfigOpenSection)("Core", &l_ConfigCore);
  104. if (rval != M64ERR_SUCCESS)
  105. {
  106. fprintf(stderr, "Error: failed to open 'Core' configuration section\n");
  107. return rval;
  108. }
  109. rval = (*ConfigOpenSection)("Video-General", &l_ConfigVideo);
  110. if (rval != M64ERR_SUCCESS)
  111. {
  112. fprintf(stderr, "Error: failed to open 'Video-General' configuration section\n");
  113. return rval;
  114. }
  115. rval = (*ConfigOpenSection)("UI-Console", &l_ConfigUI);
  116. if (rval != M64ERR_SUCCESS)
  117. {
  118. fprintf(stderr, "Error: failed to open 'UI-Console' configuration section\n");
  119. return rval;
  120. }
  121. /* Set default values for my Config parameters */
  122. (*ConfigSetDefaultString)(l_ConfigUI, "PluginDir", OSAL_CURRENT_DIR, "Directory in which to search for plugins");
  123. (*ConfigSetDefaultString)(l_ConfigUI, "VideoPlugin", "mupen64plus-video-rice" OSAL_DLL_EXTENSION, "Filename of video plugin");
  124. (*ConfigSetDefaultString)(l_ConfigUI, "AudioPlugin", "mupen64plus-audio-sdl" OSAL_DLL_EXTENSION, "Filename of audio plugin");
  125. (*ConfigSetDefaultString)(l_ConfigUI, "InputPlugin", "mupen64plus-input-sdl" OSAL_DLL_EXTENSION, "Filename of input plugin");
  126. (*ConfigSetDefaultString)(l_ConfigUI, "RspPlugin", "mupen64plus-rsp-hle" OSAL_DLL_EXTENSION, "Filename of RSP plugin");
  127. return M64ERR_SUCCESS;
  128. }
  129. static m64p_error SaveConfigurationOptions(void)
  130. {
  131. /* if shared data directory was given on the command line, write it into the config file */
  132. if (l_DataDirPath != NULL)
  133. (*ConfigSetParameter)(l_ConfigCore, "SharedDataPath", M64TYPE_STRING, l_DataDirPath);
  134. /* if any plugin filepaths were given on the command line, write them into the config file */
  135. if (g_PluginDir != NULL)
  136. (*ConfigSetParameter)(l_ConfigUI, "PluginDir", M64TYPE_STRING, g_PluginDir);
  137. if (g_GfxPlugin != NULL)
  138. (*ConfigSetParameter)(l_ConfigUI, "VideoPlugin", M64TYPE_STRING, g_GfxPlugin);
  139. if (g_AudioPlugin != NULL)
  140. (*ConfigSetParameter)(l_ConfigUI, "AudioPlugin", M64TYPE_STRING, g_AudioPlugin);
  141. if (g_InputPlugin != NULL)
  142. (*ConfigSetParameter)(l_ConfigUI, "InputPlugin", M64TYPE_STRING, g_InputPlugin);
  143. if (g_RspPlugin != NULL)
  144. (*ConfigSetParameter)(l_ConfigUI, "RspPlugin", M64TYPE_STRING, g_RspPlugin);
  145. return (*ConfigSaveFile)();
  146. }
  147. /*********************************************************************************************************
  148. * Command-line parsing
  149. */
  150. static void printUsage(const char *progname)
  151. {
  152. printf("Usage: %s [parameters] [romfile]\n"
  153. "\n"
  154. "Parameters:\n"
  155. " --noosd : disable onscreen display\n"
  156. " --osd : enable onscreen display\n"
  157. " --fullscreen : use fullscreen display mode\n"
  158. " --windowed : use windowed display mode\n"
  159. " --resolution (res) : display resolution (640x480, 800x600, 1024x768, etc)\n"
  160. " --nospeedlimit : disable core speed limiter (should be used with dummy audio plugin)\n"
  161. " --cheats (cheat-spec) : enable or list cheat codes for the given rom file\n"
  162. " --corelib (filepath) : use core library (filepath) (can be only filename or full path)\n"
  163. " --configdir (dir) : force configation directory to (dir); should contain mupen64plus.conf\n"
  164. " --datadir (dir) : search for shared data files (.ini files, languages, etc) in (dir)\n"
  165. " --plugindir (dir) : search for plugins in (dir)\n"
  166. " --sshotdir (dir) : set screenshot directory to (dir)\n"
  167. " --gfx (plugin-spec) : use gfx plugin given by (plugin-spec)\n"
  168. " --audio (plugin-spec) : use audio plugin given by (plugin-spec)\n"
  169. " --input (plugin-spec) : use input plugin given by (plugin-spec)\n"
  170. " --rsp (plugin-spec) : use rsp plugin given by (plugin-spec)\n"
  171. " --emumode (mode) : set emu mode to: 0=Pure Interpreter 1=Interpreter 2=DynaRec\n"
  172. " --testshots (list) : take screenshots at frames given in comma-separated (list), then quit\n"
  173. " --pifrom (filepath) : boot using PIF ROM (filepath) (can be only filename or full path)\n"
  174. " --set (param-spec) : set a configuration variable, format: ParamSection[ParamName]=Value\n"
  175. " --core-compare-send : use the Core Comparison debugging feature, in data sending mode\n"
  176. " --core-compare-recv : use the Core Comparison debugging feature, in data receiving mode\n"
  177. " --saveoptions : save the given command-line options in configuration file for future\n"
  178. " --verbose : print lots of information\n"
  179. " --help : see this help message\n\n"
  180. "(plugin-spec):\n"
  181. " (pluginname) : filename (without path) of plugin to find in plugin directory\n"
  182. " (pluginpath) : full path and filename of plugin\n"
  183. " 'dummy' : use dummy plugin\n\n"
  184. "(cheat-spec):\n"
  185. " 'list' : show all of the available cheat codes\n"
  186. " 'all' : enable all of the available cheat codes\n"
  187. " (codelist) : a comma-separated list of cheat code numbers to enable,\n"
  188. " with dashes to use code variables (ex 1-2 to use cheat 1 option 2)\n"
  189. "\n", progname);
  190. return;
  191. }
  192. static int SetConfigParameter(const char *ParamSpec)
  193. {
  194. char *ParsedString, *VarName, *VarValue;
  195. m64p_handle ConfigSection;
  196. m64p_type VarType;
  197. m64p_error rval;
  198. if (ParamSpec == NULL)
  199. {
  200. fprintf(stderr, "UI-Console Error: ParamSpec is NULL in SetConfigParameter()\n");
  201. return 1;
  202. }
  203. /* make a copy of the input string */
  204. ParsedString = (char *) malloc(strlen(ParamSpec) + 1);
  205. if (ParsedString == NULL)
  206. {
  207. fprintf(stderr, "UI-Console Error: SetConfigParameter() couldn't allocate memory for temporary string.\n");
  208. return 2;
  209. }
  210. strcpy(ParsedString, ParamSpec);
  211. /* parse it for the simple section[name]=value format */
  212. VarName = strchr(ParsedString, '[');
  213. if (VarName != NULL)
  214. {
  215. *VarName++ = 0;
  216. VarValue = strchr(VarName, ']');
  217. if (VarValue != NULL)
  218. {
  219. *VarValue++ = 0;
  220. }
  221. }
  222. if (VarName == NULL || VarValue == NULL || *VarValue != '=')
  223. {
  224. fprintf(stderr, "UI-Console Error: invalid (param-spec) '%s'\n", ParamSpec);
  225. free(ParsedString);
  226. return 3;
  227. }
  228. VarValue++;
  229. /* then set the value */
  230. rval = (*ConfigOpenSection)(ParsedString, &ConfigSection);
  231. if (rval != M64ERR_SUCCESS)
  232. {
  233. fprintf(stderr, "UI-Console Error: SetConfigParameter failed to open config section '%s'\n", ParsedString);
  234. free(ParsedString);
  235. return 4;
  236. }
  237. if ((*ConfigGetParameterType)(ConfigSection, VarName, &VarType) == M64ERR_SUCCESS)
  238. {
  239. switch(VarType)
  240. {
  241. int ValueInt;
  242. float ValueFloat;
  243. case M64TYPE_INT:
  244. ValueInt = atoi(VarValue);
  245. ConfigSetParameter(ConfigSection, VarName, M64TYPE_INT, &ValueInt);
  246. break;
  247. case M64TYPE_FLOAT:
  248. ValueFloat = (float) atof(VarValue);
  249. ConfigSetParameter(ConfigSection, VarName, M64TYPE_FLOAT, &ValueFloat);
  250. break;
  251. case M64TYPE_BOOL:
  252. ValueInt = (int) (osal_insensitive_strcmp(VarValue, "true") == 0);
  253. ConfigSetParameter(ConfigSection, VarName, M64TYPE_BOOL, &ValueInt);
  254. break;
  255. case M64TYPE_STRING:
  256. ConfigSetParameter(ConfigSection, VarName, M64TYPE_STRING, VarValue);
  257. break;
  258. default:
  259. fprintf(stderr, "UI-Console Error: invalid VarType in SetConfigParameter()\n");
  260. return 5;
  261. }
  262. }
  263. else
  264. {
  265. ConfigSetParameter(ConfigSection, VarName, M64TYPE_STRING, VarValue);
  266. }
  267. free(ParsedString);
  268. return 0;
  269. }
  270. static int *ParseNumberList(const char *InputString, int *ValuesFound)
  271. {
  272. const char *str;
  273. int *OutputList;
  274. /* count the number of integers in the list */
  275. int values = 1;
  276. str = InputString;
  277. while ((str = strchr(str, ',')) != NULL)
  278. {
  279. str++;
  280. values++;
  281. }
  282. /* create a list and populate it with the frame counter values at which to take screenshots */
  283. if ((OutputList = (int *) malloc(sizeof(int) * (values + 1))) != NULL)
  284. {
  285. int idx = 0;
  286. str = InputString;
  287. while (str != NULL)
  288. {
  289. OutputList[idx++] = atoi(str);
  290. str = strchr(str, ',');
  291. if (str != NULL) str++;
  292. }
  293. OutputList[idx] = 0;
  294. }
  295. if (ValuesFound != NULL)
  296. *ValuesFound = values;
  297. return OutputList;
  298. }
  299. static int ParseCommandLineInitial(int argc, const char **argv)
  300. {
  301. int i;
  302. /* look through commandline options */
  303. for (i = 1; i < argc; i++)
  304. {
  305. int ArgsLeft = argc - i - 1;
  306. if (strcmp(argv[i], "--corelib") == 0 && ArgsLeft >= 1)
  307. {
  308. l_CoreLibPath = argv[i+1];
  309. i++;
  310. }
  311. else if (strcmp(argv[i], "--configdir") == 0 && ArgsLeft >= 1)
  312. {
  313. l_ConfigDirPath = argv[i+1];
  314. i++;
  315. }
  316. else if (strcmp(argv[i], "--datadir") == 0 && ArgsLeft >= 1)
  317. {
  318. l_DataDirPath = argv[i+1];
  319. i++;
  320. }
  321. else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0)
  322. {
  323. printUsage(argv[0]);
  324. return 1;
  325. }
  326. }
  327. return 0;
  328. }
  329. static m64p_error ParseCommandLineFinal(int argc, const char **argv)
  330. {
  331. int i;
  332. /* parse commandline options */
  333. for (i = 1; i < argc; i++)
  334. {
  335. int ArgsLeft = argc - i - 1;
  336. if (strcmp(argv[i], "--noosd") == 0)
  337. {
  338. int Osd = 0;
  339. (*ConfigSetParameter)(l_ConfigCore, "OnScreenDisplay", M64TYPE_BOOL, &Osd);
  340. }
  341. else if (strcmp(argv[i], "--osd") == 0)
  342. {
  343. int Osd = 1;
  344. (*ConfigSetParameter)(l_ConfigCore, "OnScreenDisplay", M64TYPE_BOOL, &Osd);
  345. }
  346. else if (strcmp(argv[i], "--fullscreen") == 0)
  347. {
  348. int Fullscreen = 1;
  349. (*ConfigSetParameter)(l_ConfigVideo, "Fullscreen", M64TYPE_BOOL, &Fullscreen);
  350. }
  351. else if (strcmp(argv[i], "--windowed") == 0)
  352. {
  353. int Fullscreen = 0;
  354. (*ConfigSetParameter)(l_ConfigVideo, "Fullscreen", M64TYPE_BOOL, &Fullscreen);
  355. }
  356. else if (strcmp(argv[i], "--nospeedlimit") == 0)
  357. {
  358. int EnableSpeedLimit = 0;
  359. if (g_CoreAPIVersion < 0x020001)
  360. fprintf(stderr, "Warning: core library doesn't support --nospeedlimit\n");
  361. else
  362. {
  363. if ((*CoreDoCommand)(M64CMD_CORE_STATE_SET, M64CORE_SPEED_LIMITER, &EnableSpeedLimit) != M64ERR_SUCCESS)
  364. fprintf(stderr, "Error: core gave error while setting --nospeedlimit option\n");
  365. }
  366. }
  367. else if ((strcmp(argv[i], "--corelib") == 0 || strcmp(argv[i], "--configdir") == 0 ||
  368. strcmp(argv[i], "--datadir") == 0) && ArgsLeft >= 1)
  369. { /* these are handled in ParseCommandLineInitial */
  370. i++;
  371. }
  372. else if (strcmp(argv[i], "--resolution") == 0 && ArgsLeft >= 1)
  373. {
  374. const char *res = argv[i+1];
  375. int xres, yres;
  376. i++;
  377. if (sscanf(res, "%ix%i", &xres, &yres) != 2)
  378. fprintf(stderr, "Warning: couldn't parse resolution '%s'\n", res);
  379. else
  380. {
  381. (*ConfigSetParameter)(l_ConfigVideo, "ScreenWidth", M64TYPE_INT, &xres);
  382. (*ConfigSetParameter)(l_ConfigVideo, "ScreenHeight", M64TYPE_INT, &yres);
  383. }
  384. }
  385. else if (strcmp(argv[i], "--cheats") == 0 && ArgsLeft >= 1)
  386. {
  387. if (strcmp(argv[i+1], "all") == 0)
  388. l_CheatMode = CHEAT_ALL;
  389. else if (strcmp(argv[i+1], "list") == 0)
  390. l_CheatMode = CHEAT_SHOW_LIST;
  391. else
  392. {
  393. l_CheatMode = CHEAT_LIST;
  394. l_CheatNumList = (char*) argv[i+1];
  395. }
  396. i++;
  397. }
  398. else if (strcmp(argv[i], "--plugindir") == 0 && ArgsLeft >= 1)
  399. {
  400. g_PluginDir = argv[i+1];
  401. i++;
  402. }
  403. else if (strcmp(argv[i], "--sshotdir") == 0 && ArgsLeft >= 1)
  404. {
  405. (*ConfigSetParameter)(l_ConfigCore, "ScreenshotPath", M64TYPE_STRING, argv[i+1]);
  406. i++;
  407. }
  408. else if (strcmp(argv[i], "--gfx") == 0 && ArgsLeft >= 1)
  409. {
  410. g_GfxPlugin = argv[i+1];
  411. i++;
  412. }
  413. else if (strcmp(argv[i], "--audio") == 0 && ArgsLeft >= 1)
  414. {
  415. g_AudioPlugin = argv[i+1];
  416. i++;
  417. }
  418. else if (strcmp(argv[i], "--input") == 0 && ArgsLeft >= 1)
  419. {
  420. g_InputPlugin = argv[i+1];
  421. i++;
  422. }
  423. else if (strcmp(argv[i], "--rsp") == 0 && ArgsLeft >= 1)
  424. {
  425. g_RspPlugin = argv[i+1];
  426. i++;
  427. }
  428. else if (strcmp(argv[i], "--emumode") == 0 && ArgsLeft >= 1)
  429. {
  430. int emumode = atoi(argv[i+1]);
  431. i++;
  432. if (emumode < 0 || emumode > 2)
  433. {
  434. fprintf(stderr, "Warning: invalid --emumode value '%i'\n", emumode);
  435. continue;
  436. }
  437. if (emumode == 2 && !(g_CoreCapabilities & M64CAPS_DYNAREC))
  438. {
  439. fprintf(stderr, "Warning: Emulator core doesn't support Dynamic Recompiler.\n");
  440. emumode = 1;
  441. }
  442. (*ConfigSetParameter)(l_ConfigCore, "R4300Emulator", M64TYPE_INT, &emumode);
  443. }
  444. else if (strcmp(argv[i], "--testshots") == 0 && ArgsLeft >= 1)
  445. {
  446. l_TestShotList = ParseNumberList(argv[i+1], NULL);
  447. i++;
  448. }
  449. else if (strcmp(argv[i], "--pifrom") == 0 && ArgsLeft >= 1)
  450. {
  451. l_PifRomPath = argv[i+1];
  452. i++;
  453. }
  454. else if (strcmp(argv[i], "--set") == 0 && ArgsLeft >= 1)
  455. {
  456. if (SetConfigParameter(argv[i+1]) != 0)
  457. return M64ERR_INPUT_INVALID;
  458. i++;
  459. }
  460. else if (strcmp(argv[i], "--core-compare-send") == 0)
  461. {
  462. l_CoreCompareMode = 1;
  463. }
  464. else if (strcmp(argv[i], "--core-compare-recv") == 0)
  465. {
  466. l_CoreCompareMode = 2;
  467. }
  468. else if (strcmp(argv[i], "--saveoptions") == 0)
  469. {
  470. l_SaveOptions = 1;
  471. }
  472. else if (ArgsLeft == 0)
  473. {
  474. /* this is the last arg, it should be a ROM filename */
  475. l_ROMFilepath = argv[i];
  476. return M64ERR_SUCCESS;
  477. }
  478. else if (strcmp(argv[i], "--verbose") == 0)
  479. {
  480. g_Verbose = 1;
  481. }
  482. else
  483. {
  484. fprintf(stderr, "Warning: unrecognized command-line parameter '%s'\n", argv[i]);
  485. }
  486. /* continue argv loop */
  487. }
  488. /* missing ROM filepath */
  489. fprintf(stderr, "Error: no ROM filepath given\n");
  490. return M64ERR_INPUT_INVALID;
  491. }
  492. static unsigned char *LoadFileToMemory(const char *Path, long *length)
  493. {
  494. FILE *fPtr = fopen(Path, "rb");
  495. if (fPtr == NULL)
  496. {
  497. fprintf(stderr, "Error: couldn't open file '%s' for reading.\n", Path);
  498. return NULL;
  499. }
  500. /* get the length of the file, allocate memory buffer, load it from disk */
  501. *length = 0;
  502. fseek(fPtr, 0L, SEEK_END);
  503. *length = ftell(fPtr);
  504. fseek(fPtr, 0L, SEEK_SET);
  505. unsigned char *buffer = (unsigned char *) malloc(*length);
  506. if (buffer == NULL)
  507. {
  508. fprintf(stderr, "Error: couldn't allocate %li-byte buffer for file '%s'.\n", *length, Path);
  509. fclose(fPtr);
  510. return NULL;
  511. }
  512. if (fread(buffer, 1, *length, fPtr) != *length)
  513. {
  514. fprintf(stderr, "Error: couldn't read %li bytes from ROM image file '%s'.\n", *length, Path);
  515. free(buffer);
  516. fclose(fPtr);
  517. return NULL;
  518. }
  519. fclose(fPtr);
  520. return buffer;
  521. }
  522. /*********************************************************************************************************
  523. * main function
  524. */
  525. int main(int argc, char *argv[])
  526. {
  527. int i;
  528. printf(" __ __ __ _ _ ____ _ \n");
  529. printf("| \\/ |_ _ _ __ ___ _ __ / /_ | || | | _ \\| |_ _ ___ \n");
  530. printf("| |\\/| | | | | '_ \\ / _ \\ '_ \\| '_ \\| || |_| |_) | | | | / __| \n");
  531. printf("| | | | |_| | |_) | __/ | | | (_) |__ _| __/| | |_| \\__ \\ \n");
  532. printf("|_| |_|\\__,_| .__/ \\___|_| |_|\\___/ |_| |_| |_|\\__,_|___/ \n");
  533. printf(" |_| http://code.google.com/p/mupen64plus/ \n");
  534. printf("%s Version %i.%i.%i\n\n", CONSOLE_UI_NAME, VERSION_PRINTF_SPLIT(CONSOLE_UI_VERSION));
  535. /* bootstrap some special parameters from the command line */
  536. if (ParseCommandLineInitial(argc, (const char **) argv) != 0)
  537. return 1;
  538. /* load the Mupen64Plus core library */
  539. if (AttachCoreLib(l_CoreLibPath) != M64ERR_SUCCESS)
  540. return 2;
  541. /* start the Mupen64Plus core library, load the configuration file */
  542. m64p_error rval = (*CoreStartup)(CORE_API_VERSION, l_ConfigDirPath, l_DataDirPath, "Core", DebugCallback, NULL, NULL);
  543. if (rval != M64ERR_SUCCESS)
  544. {
  545. printf("UI-console: error starting Mupen64Plus core library.\n");
  546. DetachCoreLib();
  547. return 3;
  548. }
  549. /* Open configuration sections */
  550. rval = OpenConfigurationHandles();
  551. if (rval != M64ERR_SUCCESS)
  552. {
  553. (*CoreShutdown)();
  554. DetachCoreLib();
  555. return 4;
  556. }
  557. /* parse command-line options */
  558. rval = ParseCommandLineFinal(argc, (const char **) argv);
  559. if (rval != M64ERR_SUCCESS)
  560. {
  561. (*CoreShutdown)();
  562. DetachCoreLib();
  563. return 5;
  564. }
  565. /* Handle the core comparison feature */
  566. if (l_CoreCompareMode != 0 && !(g_CoreCapabilities & M64CAPS_CORE_COMPARE))
  567. {
  568. printf("UI-console: can't use --core-compare feature with this Mupen64Plus core library.\n");
  569. DetachCoreLib();
  570. return 6;
  571. }
  572. compare_core_init(l_CoreCompareMode);
  573. /* save the given command-line options in configuration file if requested */
  574. if (l_SaveOptions)
  575. SaveConfigurationOptions();
  576. /* load ROM image */
  577. long romlength;
  578. unsigned char *ROM_buffer = LoadFileToMemory(l_ROMFilepath, &romlength);
  579. if (ROM_buffer == NULL)
  580. {
  581. fprintf(stderr, "Error: couldn't load ROM image file '%s'.\n", l_ROMFilepath);
  582. (*CoreShutdown)();
  583. DetachCoreLib();
  584. return 7; // Errors 8 and 9 are deprecated
  585. }
  586. /* Try to load the ROM image into the core */
  587. if ((*CoreDoCommand)(M64CMD_ROM_OPEN, (int) romlength, ROM_buffer) != M64ERR_SUCCESS)
  588. {
  589. fprintf(stderr, "Error: core failed to open ROM image file '%s'.\n", l_ROMFilepath);
  590. free(ROM_buffer);
  591. (*CoreShutdown)();
  592. DetachCoreLib();
  593. return 10;
  594. }
  595. free(ROM_buffer); /* the core copies the ROM image, so we can release this buffer immediately */
  596. /* handle the cheat codes */
  597. CheatStart(l_CheatMode, l_CheatNumList);
  598. if (l_CheatMode == CHEAT_SHOW_LIST)
  599. {
  600. (*CoreDoCommand)(M64CMD_ROM_CLOSE, 0, NULL);
  601. (*CoreShutdown)();
  602. DetachCoreLib();
  603. return 11;
  604. }
  605. /* search for and load plugins */
  606. rval = PluginSearchLoad(l_ConfigUI);
  607. if (rval != M64ERR_SUCCESS)
  608. {
  609. (*CoreDoCommand)(M64CMD_ROM_CLOSE, 0, NULL);
  610. (*CoreShutdown)();
  611. DetachCoreLib();
  612. return 12;
  613. }
  614. /* attach plugins to core */
  615. for (i = 0; i < 4; i++)
  616. {
  617. if ((*CoreAttachPlugin)(g_PluginMap[i].type, g_PluginMap[i].handle) != M64ERR_SUCCESS)
  618. {
  619. fprintf(stderr, "UI-Console: error from core while attaching %s plugin.\n", g_PluginMap[i].name);
  620. (*CoreDoCommand)(M64CMD_ROM_CLOSE, 0, NULL);
  621. (*CoreShutdown)();
  622. DetachCoreLib();
  623. return 13;
  624. }
  625. }
  626. /* set up Frame Callback if --testshots is enabled */
  627. if (l_TestShotList != NULL)
  628. {
  629. if ((*CoreDoCommand)(M64CMD_SET_FRAME_CALLBACK, 0, FrameCallback) != M64ERR_SUCCESS)
  630. {
  631. fprintf(stderr, "UI-Console: warning: couldn't set frame callback, so --testshots won't work.\n");
  632. }
  633. }
  634. /* load PIF ROM if one was supplied */
  635. if (l_PifRomPath != NULL)
  636. {
  637. long pifromlength;
  638. unsigned char *PIFROM_buffer = LoadFileToMemory(l_PifRomPath, &pifromlength);
  639. if (PIFROM_buffer == NULL)
  640. {
  641. fprintf(stderr, "UI-Console: warning: couldn't load PIF ROM file '%s', will boot normally.\n", l_PifRomPath);
  642. }
  643. else
  644. {
  645. if ((*CoreDoCommand)(M64CMD_PIFROM_OPEN, (int)pifromlength, PIFROM_buffer) != M64ERR_SUCCESS)
  646. {
  647. fprintf(stderr, "UI-Console: warning: core rejected PIF ROM, will boot normally.\n");
  648. }
  649. free(PIFROM_buffer);
  650. }
  651. }
  652. /* run the game */
  653. (*CoreDoCommand)(M64CMD_EXECUTE, 0, NULL);
  654. /* detach plugins from core and unload them */
  655. for (i = 0; i < 4; i++)
  656. (*CoreDetachPlugin)(g_PluginMap[i].type);
  657. PluginUnload();
  658. /* close the ROM image */
  659. (*CoreDoCommand)(M64CMD_ROM_CLOSE, 0, NULL);
  660. /* save the configuration file again if --saveoptions was specified, to keep any updated parameters from the core/plugins */
  661. if (l_SaveOptions)
  662. SaveConfigurationOptions();
  663. /* close the PIF ROM image (if any) */
  664. (*CoreDoCommand)(M64CMD_PIFROM_CLOSE, 0, NULL);
  665. /* Shut down and release the Core library */
  666. (*CoreShutdown)();
  667. DetachCoreLib();
  668. /* free allocated memory */
  669. if (l_TestShotList != NULL)
  670. free(l_TestShotList);
  671. return 0;
  672. }