PageRenderTime 50ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/src/main.c

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