PageRenderTime 61ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/src/main.c

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