12 #define DIE(format, ...) do { \
13 fprintf(stderr, "Died at %s:%d: ", __FILE__, __LINE__ ); \
14 fprintf(stderr, format "\n", ## __VA_ARGS__); \
20 static const struct poptOption optionsTable[] = {
21 { "disable-audio", 'a', POPT_ARG_NONE, 0, 1,
22 "disable emulation and output of audio", 0 },
23 { "display-framerate", 'r', POPT_ARG_NONE, 0, 2,
24 "Show frames per second counter in lower left corner", 0 },
25 { "skip-frames", 's', POPT_ARG_INT, 0, 3,
26 "Render only 1 in every N frames", "NUM" },
27 { "fullscreen", 'f', POPT_ARG_NONE, 0, 4,
28 "Start in fullscreen mode", 0 },
29 { "transparency", 'y', POPT_ARG_NONE, 0, 5,
30 "Enable transparency effects (slower)", 0 },
31 { "hacks", 'h', POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, 0, 6,
32 "Enable hacks (yes, speed-only, no)", "option" },
33 { "pal", 'p', POPT_ARG_NONE, 0, 7,
34 "Run in PAL mode", 0 },
35 { "ntsc", 'n', POPT_ARG_NONE, 0, 8,
36 "Run in NTSC mode", 0 },
37 { "turbo", 't', POPT_ARG_NONE, 0, 9,
38 "Turbo mode (do not try to sleep between frames)", 0 },
39 { "conf", 'c', POPT_ARG_STRING, 0, 10,
40 "Extra configuration file to load", "FILE" },
41 { "mouse", 'm', POPT_ARG_INT | POPT_ARGFLAG_OPTIONAL, 0, 11,
42 "Enable mouse on controller NUM", "NUM"},
43 { "superscope", 'e', POPT_ARG_NONE, 0, 12,
44 "Enable SuperScope", 0},
45 { "scancode", '\0', POPT_ARG_INT, 0, 100,
46 "Scancode to map", "CODE" },
47 { "button", '\0', POPT_ARG_STRING, 0, 101,
48 "SNES Button to press (A, B, X, Y, L, R, Up, Down, Left, Right)", "name" },
49 { "action", '\0', POPT_ARG_STRING, 0, 102,
50 "Emulator action to do (fullscreen, quit, ...)", "action" },
51 { "hacks-file", '\0', POPT_ARG_STRING, 0, 200,
52 "Path to snesadvance.dat file", "FILE" },
57 static unsigned short buttonNameToBit(const char *s) {
58 if (strcasecmp(s, "A") == 0) {
60 } else if (strcasecmp(s, "B") == 0) {
62 } else if (strcasecmp(s, "X") == 0) {
64 } else if (strcasecmp(s, "Y") == 0) {
66 } else if (strcasecmp(s, "L") == 0) {
68 } else if (strcasecmp(s, "R") == 0) {
70 } else if (strcasecmp(s, "UP") == 0) {
72 } else if (strcasecmp(s, "DOWN") == 0) {
73 return SNES_DOWN_MASK;
74 } else if (strcasecmp(s, "LEFT") == 0) {
75 return SNES_LEFT_MASK;
76 } else if (strcasecmp(s, "RIGHT") == 0) {
77 return SNES_RIGHT_MASK;
78 } else if (strcasecmp(s, "START") == 0) {
79 return SNES_START_MASK;
80 } else if (strcasecmp(s, "SELECT") == 0) {
81 return SNES_SELECT_MASK;
83 DIE("Bad button name: %s\n", s);
87 static unsigned char actionNameToBit(const char *s) {
88 if (strcasecmp(s, "quit") == 0) {
90 } else if (strcasecmp(s, "fullscreen") == 0) {
91 return kActionToggleFullscreen;
93 DIE("Bad action name: %s\n", s);
97 const char * S9xFiletitle(const char * f)
101 const char * p = strrchr (f, '.');
109 const char * S9xBasename(const char * f)
111 const char * p = strrchr (f, '/');
119 const char * S9xGetFilename(const char * ext)
121 static char filename [PATH_MAX + 1];
122 sprintf(filename, "%s%s", Config.romFile, ext);
127 static void loadDefaults()
129 ZeroMemory(&Settings, sizeof(Settings));
130 ZeroMemory(&Config, sizeof(Config));
132 Config.quitting = false;
133 Config.enableAudio = true;
134 Config.fullscreen = false;
137 Settings.JoystickEnabled = FALSE;
138 Settings.SoundPlaybackRate = 22050;
139 Settings.Stereo = TRUE;
140 Settings.SoundBufferSize = 0;
141 Settings.CyclesPercentage = 100;
142 Settings.DisableSoundEcho = FALSE;
143 Settings.APUEnabled = FALSE;
144 Settings.H_Max = SNES_CYCLES_PER_SCANLINE;
145 Settings.SkipFrames = AUTO_FRAMERATE;
146 Settings.Shutdown = Settings.ShutdownMaster = TRUE;
147 Settings.FrameTimePAL = 20000; // in usecs
148 Settings.FrameTimeNTSC = 16667;
149 Settings.FrameTime = Settings.FrameTimeNTSC;
150 Settings.DisableSampleCaching = FALSE;
151 Settings.DisableMasterVolume = FALSE;
152 Settings.Mouse = FALSE;
153 Settings.SuperScope = FALSE;
154 Settings.MultiPlayer5 = FALSE;
155 Settings.ControllerOption = SNES_JOYPAD;
157 Settings.ForceTransparency = FALSE;
158 Settings.Transparency = FALSE;
159 Settings.SixteenBit = TRUE;
161 Settings.SupportHiRes = FALSE;
162 Settings.NetPlay = FALSE;
163 Settings.ServerName [0] = 0;
164 Settings.AutoSaveDelay = 30;
165 Settings.ApplyCheats = FALSE;
166 Settings.TurboMode = FALSE;
167 Settings.TurboSkipFrames = 15;
168 //Settings.ThreadSound = FALSE;
169 //Settings.SoundSync = FALSE;
170 //Settings.NoPatch = true;
172 Settings.ForcePAL = FALSE;
173 Settings.ForceNTSC = FALSE;
175 Settings.HacksEnabled = FALSE;
176 Settings.HacksFilter = FALSE;
178 Settings.HBlankStart = (256 * Settings.H_Max) / SNES_HCOUNTER_MAX;
180 Settings.AutoSaveDelay = 15*60; // Autosave each 15 minutes.
183 void S9xSetRomFile(const char * path)
185 char drive[1], dir[PATH_MAX], fname[PATH_MAX], ext[PATH_MAX];
187 _splitpath (path, drive, dir, fname, ext);
188 sprintf(Config.romFile, "%s%s%s", dir, strlen(dir) > 0 ? "/" : "", fname);
191 static bool gotRomFile()
193 return Config.romFile[0] != '\0';
196 static void setHacks(const char * value)
198 // Unconditionally enable hacks even if no argument passed
199 Settings.HacksEnabled = TRUE;
203 if (strcasecmp(value, "speed-only") == 0 ||
204 strcasecmp(value, "speed") == 0 ||
205 strcasecmp(value, "s") == 0) {
206 Settings.HacksFilter = TRUE;
207 } else if (strcasecmp(value, "yes") == 0 ||
208 strcasecmp(value, "y") == 0) {
210 } else if (strcasecmp(value, "no") == 0 ||
211 strcasecmp(value, "n") == 0) {
212 Settings.HacksEnabled = FALSE;
214 // Hack: the user probably wants to enable hacks
215 // and use this argument as the ROM file.
216 // Wonder why popt does not support this or if there's a better way.
217 S9xSetRomFile(value);
221 static void loadConfig(poptContext optCon, const char * file)
225 const char ** newargv;
228 fp = fopen (file, "r");
230 fprintf(stderr, "Cannot open config file %s\n", file);
234 ret = poptConfigFileToString (fp, &out, 0);
236 DIE("Cannot parse config file %s. ret=%d\n", file, ret);
238 poptParseArgvString(out, &newargc, &newargv);
240 poptStuffArgs(optCon, newargv);
244 /* XXX: currently leaking newargv */
247 static void parseArgs(poptContext optCon)
250 unsigned char scancode = 0;
252 while ((rc = poptGetNextOpt(optCon)) > 0) {
256 Config.enableAudio = false;
259 Settings.DisplayFrameRate = TRUE;
262 Settings.SkipFrames = atoi(poptGetOptArg(optCon));
265 Config.fullscreen = true;
268 Settings.SixteenBit = TRUE;
269 Settings.Transparency = TRUE;
272 Settings.HacksEnabled = TRUE;
273 setHacks(poptGetOptArg(optCon));
276 Settings.ForcePAL = TRUE;
279 Settings.ForceNTSC = TRUE;
282 Settings.TurboMode = TRUE;
285 loadConfig(optCon, poptGetOptArg(optCon));
288 val = poptGetOptArg(optCon);
289 Settings.Mouse = TRUE;
290 if (!val || atoi(val) <= 1) {
291 // Enable mouse on first controller
292 Settings.ControllerOption = SNES_MOUSE_SWAPPED;
294 // Enable mouse on second controller
295 Settings.ControllerOption = SNES_MOUSE;
299 Settings.SuperScope = TRUE;
300 Settings.ControllerOption = SNES_SUPERSCOPE;
303 scancode = atoi(poptGetOptArg(optCon));
306 Config.joypad1Mapping[scancode] |=
307 buttonNameToBit(poptGetOptArg(optCon));
310 Config.action[scancode] |=
311 actionNameToBit(poptGetOptArg(optCon));
314 strcpy(Config.hacksFile, poptGetOptArg(optCon));
317 DIE("Invalid popt argument (this is a bug): %d", rc);
323 /* an error occurred during option processing */
324 fprintf(stderr, "%s: %s\n",
325 poptBadOption(optCon, 0),
330 /* if there's an extra unparsed arg it's our rom file */
331 const char * extra_arg = poptGetArg(optCon);
333 S9xSetRomFile(extra_arg);
336 void S9xLoadConfig(int argc, const char ** argv)
339 poptGetContext("drnoksnes", argc, argv, optionsTable, 0);
340 poptSetOtherOptionHelp(optCon, "<rom>");
345 // Read config file ~/apps/DrNokSnes.txt
346 char defConfFile[PATH_MAX];
347 sprintf(defConfFile, "%s/%s", getenv("HOME"), "apps/DrNokSnes.txt");
348 loadConfig(optCon, defConfFile);
350 // Command line parameters (including --conf args)
353 if (!gotRomFile() && !hgwLaunched) {
354 // User did not specify a ROM file,
355 // and we're not being launched from D-Bus.
356 fprintf(stderr, "You need to specify a ROM, like this:\n");
357 poptPrintUsage(optCon, stdout, 0);
358 poptFreeContext(optCon);
362 poptFreeContext(optCon);