Gizmondo port updated to 1.51b
[libpicofe.git] / common / config.c
CommitLineData
c51bd2fe 1/*
2 * Human-readable config file management for PicoDrive
3 * (c)
4 */
5
7836e87c 6#include <stdio.h>
c51bd2fe 7#include <string.h>
8#include <stdlib.h>
9#include "config.h"
7836e87c 10#include "lprintf.h"
11
12static char *mystrip(char *str);
13
14#ifndef _MSC_VER
15
c51bd2fe 16#include "menu.h"
17#include "emu.h"
18#include <Pico/Pico.h>
19
20extern menu_entry opt_entries[];
21extern menu_entry opt2_entries[];
22extern menu_entry cdopt_entries[];
6589c840 23extern menu_entry ctrlopt_entries[];
c51bd2fe 24extern const int opt_entry_count;
25extern const int opt2_entry_count;
26extern const int cdopt_entry_count;
6589c840 27extern const int ctrlopt_entry_count;
960a8e27 28#ifdef PSP
29extern menu_entry opt3_entries[];
30extern const int opt3_entry_count;
31#endif
c51bd2fe 32
960a8e27 33static menu_entry *cfg_opts[] =
34{
35 opt_entries,
36 opt2_entries,
37 cdopt_entries,
6589c840 38 ctrlopt_entries,
960a8e27 39#ifdef PSP
40 opt3_entries,
41#endif
42};
43
44static const int *cfg_opt_counts[] =
45{
46 &opt_entry_count,
47 &opt2_entry_count,
48 &cdopt_entry_count,
6589c840 49 &ctrlopt_entry_count,
960a8e27 50#ifdef PSP
51 &opt3_entry_count,
52#endif
53};
c51bd2fe 54
67dfdf5f 55#define NL "\r\n"
c51bd2fe 56
57
58static int seek_sect(FILE *f, const char *section)
59{
60 char line[128], *tmp;
61 int len;
62
63 len = strlen(section);
64 // seek to the section needed
65 while (!feof(f))
66 {
67 tmp = fgets(line, sizeof(line), f);
68 if (tmp == NULL) break;
69
70 if (line[0] != '[') continue; // not section start
71 if (strncmp(line + 1, section, len) == 0 && line[len+1] == ']')
72 return 1; // found it
73 }
74
75 return 0;
76}
77
78
3e85ebdd 79static void custom_write(FILE *f, const menu_entry *me, int no_def)
c51bd2fe 80{
81 char *str, str24[24];
82
83 switch (me->id)
84 {
85 case MA_OPT_RENDERER:
dd5fd477 86 if (no_def && !((defaultConfig.s_PicoOpt^PicoOpt)&POPT_ALT_RENDERER) &&
c51bd2fe 87 !((defaultConfig.EmuOpt^currentConfig.EmuOpt)&0x80)) return;
dd5fd477 88 if (PicoOpt&POPT_ALT_RENDERER)
960a8e27 89 str =
90#ifndef PSP
91 "8bit "
92#endif
93 "fast";
c51bd2fe 94 else if (currentConfig.EmuOpt&0x80)
960a8e27 95 str =
96#ifndef PSP
97 "16bit "
98#endif
99 "accurate";
c51bd2fe 100 else
101 str = "8bit accurate";
102 fprintf(f, "Renderer = %s", str);
103 break;
104
105 case MA_OPT_SCALING:
3e85ebdd 106 if (no_def && defaultConfig.scaling == currentConfig.scaling) return;
960a8e27 107#ifdef __GP2X__
c51bd2fe 108 switch (currentConfig.scaling) {
109 default: str = "OFF"; break;
110 case 1: str = "hw horizontal"; break;
111 case 2: str = "hw horiz. + vert."; break;
112 case 3: str = "sw horizontal"; break;
113 }
114 fprintf(f, "Scaling = %s", str);
960a8e27 115#endif
c51bd2fe 116 break;
117 case MA_OPT_FRAMESKIP:
3e85ebdd 118 if (no_def && defaultConfig.Frameskip == currentConfig.Frameskip) return;
c51bd2fe 119 if (currentConfig.Frameskip < 0)
120 strcpy(str24, "Auto");
121 else sprintf(str24, "%i", currentConfig.Frameskip);
122 fprintf(f, "Frameskip = %s", str24);
123 break;
124 case MA_OPT_SOUND_QUALITY:
dd5fd477 125 if (no_def && !((defaultConfig.s_PicoOpt^PicoOpt)&POPT_EN_STEREO) &&
c51bd2fe 126 defaultConfig.s_PsndRate == PsndRate) return;
dd5fd477 127 str = (PicoOpt&POPT_EN_STEREO)?"stereo":"mono";
c51bd2fe 128 fprintf(f, "Sound Quality = %i %s", PsndRate, str);
129 break;
130 case MA_OPT_REGION:
3e85ebdd 131 if (no_def && defaultConfig.s_PicoRegion == PicoRegionOverride &&
c51bd2fe 132 defaultConfig.s_PicoAutoRgnOrder == PicoAutoRgnOrder) return;
960a8e27 133 strncpy(str24, me_region_name(PicoRegionOverride, PicoAutoRgnOrder), 23); str24[23] = 0;
134 fprintf(f, "Region = %s", mystrip(str24));
c51bd2fe 135 break;
136 case MA_OPT_CONFIRM_STATES:
3e85ebdd 137 if (no_def && !((defaultConfig.EmuOpt^currentConfig.EmuOpt)&(5<<9))) return;
c51bd2fe 138 switch ((currentConfig.EmuOpt >> 9) & 5) {
139 default: str = "OFF"; break;
140 case 1: str = "writes"; break;
141 case 4: str = "loads"; break;
142 case 5: str = "both"; break;
143 }
144 fprintf(f, "Confirm savestate = %s", str);
145 break;
146 case MA_OPT_CPU_CLOCKS:
3e85ebdd 147 if (no_def && defaultConfig.CPUclock == currentConfig.CPUclock) return;
960a8e27 148#ifdef __GP2X__
c51bd2fe 149 fprintf(f, "GP2X CPU clocks = %i", currentConfig.CPUclock);
960a8e27 150#elif defined(PSP)
151 fprintf(f, "PSP CPU clock = %i", currentConfig.CPUclock);
152#endif
c51bd2fe 153 break;
154 case MA_OPT2_GAMMA:
3e85ebdd 155 if (no_def && defaultConfig.gamma == currentConfig.gamma) return;
c51bd2fe 156 fprintf(f, "Gamma correction = %.3f", (double)currentConfig.gamma / 100.0);
157 break;
158 case MA_OPT2_SQUIDGEHACK:
3e85ebdd 159 if (no_def && !((defaultConfig.EmuOpt^currentConfig.EmuOpt)&0x0010)) return;
c51bd2fe 160 fprintf(f, "Squidgehack = %i", (currentConfig.EmuOpt&0x0010)>>4);
161 break;
162 case MA_CDOPT_READAHEAD:
3e85ebdd 163 if (no_def && defaultConfig.s_PicoCDBuffers == PicoCDBuffers) return;
c51bd2fe 164 sprintf(str24, "%i", PicoCDBuffers * 2);
165 fprintf(f, "ReadAhead buffer = %s", str24);
166 break;
960a8e27 167 /* PSP */
168 case MA_OPT3_SCALE:
169 if (no_def && defaultConfig.scale == currentConfig.scale) return;
170 fprintf(f, "Scale factor = %.2f", currentConfig.scale);
171 break;
172 case MA_OPT3_HSCALE32:
173 if (no_def && defaultConfig.hscale32 == currentConfig.hscale32) return;
174 fprintf(f, "Hor. scale (for low res. games) = %.2f", currentConfig.hscale32);
175 break;
176 case MA_OPT3_HSCALE40:
177 if (no_def && defaultConfig.hscale40 == currentConfig.hscale40) return;
178 fprintf(f, "Hor. scale (for hi res. games) = %.2f", currentConfig.hscale40);
179 break;
180 case MA_OPT3_FILTERING:
181 if (no_def && defaultConfig.scaling == currentConfig.scaling) return;
182 fprintf(f, "Bilinear filtering = %i", currentConfig.scaling);
183 break;
184 case MA_OPT3_GAMMAA:
185 if (no_def && defaultConfig.gamma == currentConfig.gamma) return;
186 fprintf(f, "Gamma adjustment = %i", currentConfig.gamma);
187 break;
188 case MA_OPT3_BLACKLVL:
189 if (no_def && defaultConfig.gamma2 == currentConfig.gamma2) return;
190 fprintf(f, "Black level = %i", currentConfig.gamma2);
191 break;
192 case MA_OPT3_VSYNC:
193 if (no_def && (defaultConfig.EmuOpt&0x12000) == (currentConfig.gamma2&0x12000)) return;
194 strcpy(str24, "never");
195 if (currentConfig.EmuOpt & 0x2000)
196 strcpy(str24, (currentConfig.EmuOpt & 0x10000) ? "sometimes" : "always");
197 fprintf(f, "Wait for vsync = %s", str24);
198 break;
c51bd2fe 199
200 default:
3e85ebdd 201 lprintf("unhandled custom_write: %i\n", me->id);
c51bd2fe 202 return;
203 }
204 fprintf(f, NL);
205}
206
367b6f1f 207
208static const char *joyKeyNames[32] =
209{
210 "UP", "DOWN", "LEFT", "RIGHT", "b1", "b2", "b3", "b4",
211 "b5", "b6", "b7", "b8", "b9", "b10", "b11", "b12",
212 "b13", "b14", "b15", "b16", "b17", "b19", "b19", "b20",
213 "b21", "b22", "b23", "b24", "b25", "b26", "b27", "b28"
214};
215
216static void keys_write(FILE *fn, const char *bind_str, const int binds[32],
960a8e27 217 const int def_binds[32], const char * const names[32], int no_defaults)
367b6f1f 218{
219 int t, i;
220 char act[48];
221
222 for (t = 0; t < 32; t++)
223 {
224 act[0] = act[31] = 0;
225 if (no_defaults && binds[t] == def_binds[t])
226 continue;
227 if (strcmp(names[t], "???") == 0) continue;
228#ifdef __GP2X__
229 if (strcmp(names[t], "SELECT") == 0) continue;
230#endif
960a8e27 231 if (binds[t] == 0 && def_binds[t] != 0) {
232 fprintf(fn, "%s %s =" NL, bind_str, names[t]); // no binds
233 continue;
234 }
235
367b6f1f 236 for (i = 0; i < sizeof(me_ctrl_actions) / sizeof(me_ctrl_actions[0]); i++) {
237 if (me_ctrl_actions[i].mask & binds[t]) {
8e708f92 238 strncpy(act, me_ctrl_actions[i].name, 31);
239 fprintf(fn, "%s %s = player%i %s" NL, bind_str, names[t],
240 ((binds[t]>>16)&1)+1, mystrip(act));
367b6f1f 241 }
242 }
367b6f1f 243
8e708f92 244 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
245 if (emuctrl_actions[i].mask & binds[t]) {
246 strncpy(act, emuctrl_actions[i].name, 31);
247 fprintf(fn, "%s %s = %s" NL, bind_str, names[t], mystrip(act));
248 }
249 }
367b6f1f 250 }
251}
252
253
3e85ebdd 254static int default_var(const menu_entry *me)
255{
256 switch (me->id)
257 {
258 case MA_OPT_ACC_TIMING:
259 case MA_OPT_ACC_SPRITES:
260 case MA_OPT_ARM940_SOUND:
261 case MA_OPT_6BUTTON_PAD:
262 case MA_OPT2_ENABLE_Z80:
263 case MA_OPT2_ENABLE_YM2612:
264 case MA_OPT2_ENABLE_SN76496:
367b6f1f 265 case MA_OPT2_SVP_DYNAREC:
3e85ebdd 266 case MA_CDOPT_CDDA:
267 case MA_CDOPT_PCM:
268 case MA_CDOPT_SAVERAM:
269 case MA_CDOPT_SCALEROT_CHIP:
270 case MA_CDOPT_BETTER_SYNC:
271 return defaultConfig.s_PicoOpt;
272
273 case MA_OPT_SHOW_FPS:
274 case MA_OPT_ENABLE_SOUND:
275 case MA_OPT_SRAM_STATES:
276 case MA_OPT2_A_SN_GAMMA:
277 case MA_OPT2_VSYNC:
278 case MA_OPT2_GZIP_STATES:
279 case MA_OPT2_NO_LAST_ROM:
280 case MA_OPT2_RAMTIMINGS:
281 case MA_CDOPT_LEDS:
282 return defaultConfig.EmuOpt;
283
6589c840 284 case MA_CTRL_TURBO_RATE:
285 return defaultConfig.turbo_rate;
286
3e85ebdd 287 case MA_OPT_SAVE_SLOT:
288 default:
289 return 0;
290 }
291}
c51bd2fe 292
293int config_writesect(const char *fname, const char *section)
294{
295 FILE *fo = NULL, *fn = NULL; // old and new
3e85ebdd 296 int no_defaults = 0; // avoid saving defaults
c51bd2fe 297 menu_entry *me;
298 int t, i, tlen, ret;
299 char line[128], *tmp;
300
301 if (section != NULL)
302 {
3e85ebdd 303 no_defaults = 1;
304
c51bd2fe 305 fo = fopen(fname, "r");
306 if (fo == NULL) {
307 fn = fopen(fname, "w");
308 goto write;
309 }
310
311 ret = seek_sect(fo, section);
312 if (!ret) {
313 // sect not found, we can simply append
314 fclose(fo); fo = NULL;
315 fn = fopen(fname, "a");
316 goto write;
317 }
318
319 // use 2 files..
320 fclose(fo);
321 rename(fname, "tmp.cfg");
322 fo = fopen("tmp.cfg", "r");
323 fn = fopen(fname, "w");
324 if (fo == NULL || fn == NULL) goto write;
325
326 // copy everything until sect
327 tlen = strlen(section);
328 while (!feof(fo))
329 {
330 tmp = fgets(line, sizeof(line), fo);
331 if (tmp == NULL) break;
332
333 if (line[0] == '[' && strncmp(line + 1, section, tlen) == 0 && line[tlen+1] == ']')
334 break;
335 fputs(line, fn);
336 }
337
338 // now skip to next sect
339 while (!feof(fo))
340 {
341 tmp = fgets(line, sizeof(line), fo);
342 if (tmp == NULL) break;
343 if (line[0] == '[') {
344 fseek(fo, -strlen(line), SEEK_CUR);
345 break;
346 }
347 }
348 if (feof(fo))
349 {
350 fclose(fo); fo = NULL;
351 remove("tmp.cfg");
352 }
353 }
354 else
355 {
356 fn = fopen(fname, "w");
357 }
358
359write:
360 if (fn == NULL) {
361 if (fo) fclose(fo);
362 return -1;
363 }
364 if (section != NULL)
365 fprintf(fn, "[%s]" NL, section);
366
367 for (t = 0; t < sizeof(cfg_opts) / sizeof(cfg_opts[0]); t++)
368 {
369 me = cfg_opts[t];
370 tlen = *(cfg_opt_counts[t]);
371 for (i = 0; i < tlen; i++, me++)
372 {
373 if (!me->need_to_save) continue;
374 if ((me->beh != MB_ONOFF && me->beh != MB_RANGE) || me->name == NULL)
3e85ebdd 375 custom_write(fn, me, no_defaults);
376 else if (me->beh == MB_ONOFF) {
377 if (!no_defaults || ((*(int *)me->var ^ default_var(me)) & me->mask))
378 fprintf(fn, "%s = %i" NL, me->name, (*(int *)me->var & me->mask) ? 1 : 0);
379 } else if (me->beh == MB_RANGE) {
6589c840 380 if (!no_defaults || (*(int *)me->var ^ default_var(me)))
3e85ebdd 381 fprintf(fn, "%s = %i" NL, me->name, *(int *)me->var);
382 }
c51bd2fe 383 }
384 }
367b6f1f 385
386 // save key config
387 keys_write(fn, "bind", currentConfig.KeyBinds, defaultConfig.KeyBinds, keyNames, no_defaults);
388 keys_write(fn, "bind_joy0", currentConfig.JoyBinds[0], defaultConfig.JoyBinds[0], joyKeyNames, 1);
389 keys_write(fn, "bind_joy1", currentConfig.JoyBinds[1], defaultConfig.JoyBinds[1], joyKeyNames, 1);
390 keys_write(fn, "bind_joy2", currentConfig.JoyBinds[2], defaultConfig.JoyBinds[2], joyKeyNames, 1);
391 keys_write(fn, "bind_joy3", currentConfig.JoyBinds[3], defaultConfig.JoyBinds[3], joyKeyNames, 1);
392
960a8e27 393#ifndef PSP
67dfdf5f 394 if (section == NULL)
395 fprintf(fn, "Sound Volume = %i" NL, currentConfig.volume);
960a8e27 396#endif
67dfdf5f 397
c51bd2fe 398 fprintf(fn, NL);
399
400 if (fo != NULL)
401 {
402 // copy whatever is left
403 while (!feof(fo))
404 {
405 tmp = fgets(line, sizeof(line), fo);
406 if (tmp == NULL) break;
407
408 fputs(line, fn);
409 }
410 fclose(fo);
411 remove("tmp.cfg");
412 }
413
414 fclose(fn);
415 return 0;
416}
417
418
c51bd2fe 419int config_writelrom(const char *fname)
420{
421 char line[128], *tmp, *optr = NULL;
422 char *old_data = NULL;
423 int size;
424 FILE *f;
425
a5365695 426 if (strlen(lastRomFile) == 0) return -1;
c51bd2fe 427
428 f = fopen(fname, "r");
429 if (f != NULL)
430 {
431 fseek(f, 0, SEEK_END);
432 size = ftell(f);
433 fseek(f, 0, SEEK_SET);
434 old_data = malloc(size + size/8);
435 if (old_data != NULL)
436 {
437 optr = old_data;
438 while (!feof(f))
439 {
440 tmp = fgets(line, sizeof(line), f);
441 if (tmp == NULL) break;
442 mystrip(line);
443 if (strncasecmp(line, "LastUsedROM", 11) == 0)
444 continue;
445 sprintf(optr, "%s", line);
446 optr += strlen(optr);
447 }
448 }
449 fclose(f);
450 }
451
452 f = fopen(fname, "w");
453 if (f == NULL) return -1;
454
455 if (old_data != NULL) {
456 fwrite(old_data, 1, optr - old_data, f);
457 free(old_data);
458 }
367b6f1f 459 fprintf(f, "LastUsedROM = %s" NL, lastRomFile);
c51bd2fe 460 fclose(f);
461 return 0;
462}
463
367b6f1f 464/* --------------------------------------------------------------------------*/
465
466int config_readlrom(const char *fname)
467{
468 char line[128], *tmp;
469 int i, len, ret = -1;
470 FILE *f;
471
472 f = fopen(fname, "r");
473 if (f == NULL) return -1;
474
475 // seek to the section needed
476 while (!feof(f))
477 {
478 tmp = fgets(line, sizeof(line), f);
479 if (tmp == NULL) break;
480
481 if (strncasecmp(line, "LastUsedROM", 11) != 0) continue;
482 len = strlen(line);
483 for (i = 0; i < len; i++)
484 if (line[i] == '#' || line[i] == '\r' || line[i] == '\n') { line[i] = 0; break; }
485 tmp = strchr(line, '=');
486 if (tmp == NULL) break;
487 tmp++;
488 mystrip(tmp);
489
490 len = sizeof(lastRomFile);
491 strncpy(lastRomFile, tmp, len);
492 lastRomFile[len-1] = 0;
493 ret = 0;
494 break;
495 }
496 fclose(f);
497 return ret;
498}
499
c51bd2fe 500
501static int custom_read(menu_entry *me, const char *var, const char *val)
502{
503 char *tmp;
504 int tmpi;
505
506 switch (me->id)
507 {
508 case MA_OPT_RENDERER:
509 if (strcasecmp(var, "Renderer") != 0) return 0;
960a8e27 510 if (strcasecmp(val, "8bit fast") == 0 || strcasecmp(val, "fast") == 0) {
dd5fd477 511 PicoOpt |= POPT_ALT_RENDERER;
c51bd2fe 512 }
960a8e27 513 else if (strcasecmp(val, "16bit accurate") == 0 || strcasecmp(val, "accurate") == 0) {
dd5fd477 514 PicoOpt &= ~POPT_ALT_RENDERER;
c51bd2fe 515 currentConfig.EmuOpt |= 0x80;
516 }
517 else if (strcasecmp(val, "8bit accurate") == 0) {
dd5fd477 518 PicoOpt &= ~POPT_ALT_RENDERER;
c51bd2fe 519 currentConfig.EmuOpt &= ~0x80;
520 }
521 else
522 return 0;
523 return 1;
524
525 case MA_OPT_SCALING:
960a8e27 526#ifdef __GP2X__
c51bd2fe 527 if (strcasecmp(var, "Scaling") != 0) return 0;
528 if (strcasecmp(val, "OFF") == 0) {
529 currentConfig.scaling = 0;
530 } else if (strcasecmp(val, "hw horizontal") == 0) {
531 currentConfig.scaling = 1;
532 } else if (strcasecmp(val, "hw horiz. + vert.") == 0) {
533 currentConfig.scaling = 2;
534 } else if (strcasecmp(val, "sw horizontal") == 0) {
535 currentConfig.scaling = 3;
536 } else
537 return 0;
538 return 1;
960a8e27 539#else
540 return 0;
541#endif
c51bd2fe 542
543 case MA_OPT_FRAMESKIP:
544 if (strcasecmp(var, "Frameskip") != 0) return 0;
545 if (strcasecmp(val, "Auto") == 0)
546 currentConfig.Frameskip = -1;
547 else currentConfig.Frameskip = atoi(val);
548 return 1;
549
550 case MA_OPT_SOUND_QUALITY:
551 if (strcasecmp(var, "Sound Quality") != 0) return 0;
552 PsndRate = strtoul(val, &tmp, 10);
553 if (PsndRate < 8000 || PsndRate > 44100)
554 PsndRate = 22050;
555 while (*tmp == ' ') tmp++;
556 if (strcasecmp(tmp, "stereo") == 0) {
dd5fd477 557 PicoOpt |= POPT_EN_STEREO;
c51bd2fe 558 } else if (strcasecmp(tmp, "mono") == 0) {
dd5fd477 559 PicoOpt &= ~POPT_EN_STEREO;
c51bd2fe 560 } else
561 return 0;
562 return 1;
563
564 case MA_OPT_REGION:
565 if (strcasecmp(var, "Region") != 0) return 0;
566 if (strncasecmp(val, "Auto: ", 6) == 0)
567 {
568 const char *p = val + 5, *end = val + strlen(val);
569 int i;
570 PicoRegionOverride = PicoAutoRgnOrder = 0;
3e85ebdd 571 for (i = 0; p < end && i < 3; i++)
572 {
573 while (*p == ' ') p++;
c51bd2fe 574 if (p[0] == 'J' && p[1] == 'P') {
575 PicoAutoRgnOrder |= 1 << (i*4);
576 } else if (p[0] == 'U' && p[1] == 'S') {
577 PicoAutoRgnOrder |= 4 << (i*4);
578 } else if (p[0] == 'E' && p[1] == 'U') {
579 PicoAutoRgnOrder |= 8 << (i*4);
580 }
3e85ebdd 581 while (*p != ' ' && *p != 0) p++;
582 if (*p == 0) break;
c51bd2fe 583 }
584 }
585 else if (strcasecmp(val, "Auto") == 0) {
586 PicoRegionOverride = 0;
587 } else if (strcasecmp(val, "Japan NTSC") == 0) {
588 PicoRegionOverride = 1;
589 } else if (strcasecmp(val, "Japan PAL") == 0) {
590 PicoRegionOverride = 2;
591 } else if (strcasecmp(val, "USA") == 0) {
592 PicoRegionOverride = 4;
593 } else if (strcasecmp(val, "Europe") == 0) {
594 PicoRegionOverride = 8;
595 } else
596 return 0;
597 return 1;
598
599 case MA_OPT_CONFIRM_STATES:
600 if (strcasecmp(var, "Confirm savestate") != 0) return 0;
601 if (strcasecmp(val, "OFF") == 0) {
367b6f1f 602 currentConfig.EmuOpt &= ~(5<<9);
c51bd2fe 603 } else if (strcasecmp(val, "writes") == 0) {
367b6f1f 604 currentConfig.EmuOpt &= ~(5<<9);
605 currentConfig.EmuOpt |= 1<<9;
c51bd2fe 606 } else if (strcasecmp(val, "loads") == 0) {
367b6f1f 607 currentConfig.EmuOpt &= ~(5<<9);
608 currentConfig.EmuOpt |= 4<<9;
c51bd2fe 609 } else if (strcasecmp(val, "both") == 0) {
367b6f1f 610 currentConfig.EmuOpt &= ~(5<<9);
611 currentConfig.EmuOpt |= 5<<9;
c51bd2fe 612 } else
613 return 0;
614 return 1;
615
616 case MA_OPT_CPU_CLOCKS:
960a8e27 617#ifdef __GP2X__
c51bd2fe 618 if (strcasecmp(var, "GP2X CPU clocks") != 0) return 0;
960a8e27 619#elif defined(PSP)
620 if (strcasecmp(var, "PSP CPU clock") != 0) return 0;
621#endif
c51bd2fe 622 currentConfig.CPUclock = atoi(val);
623 return 1;
624
625 case MA_OPT2_GAMMA:
626 if (strcasecmp(var, "Gamma correction") != 0) return 0;
627 currentConfig.gamma = (int) (atof(val) * 100.0);
628 return 1;
629
630 case MA_OPT2_SQUIDGEHACK:
631 if (strcasecmp(var, "Squidgehack") != 0) return 0;
632 tmpi = atoi(val);
633 if (tmpi) *(int *)me->var |= me->mask;
634 else *(int *)me->var &= ~me->mask;
635 return 1;
636
637 case MA_CDOPT_READAHEAD:
638 if (strcasecmp(var, "ReadAhead buffer") != 0) return 0;
639 PicoCDBuffers = atoi(val) / 2;
640 return 1;
641
960a8e27 642 /* PSP */
643 case MA_OPT3_SCALE:
644 if (strcasecmp(var, "Scale factor") != 0) return 0;
645 currentConfig.scale = atof(val);
646 return 1;
647 case MA_OPT3_HSCALE32:
648 if (strcasecmp(var, "Hor. scale (for low res. games)") != 0) return 0;
649 currentConfig.hscale32 = atof(val);
650 return 1;
651 case MA_OPT3_HSCALE40:
652 if (strcasecmp(var, "Hor. scale (for hi res. games)") != 0) return 0;
653 currentConfig.hscale40 = atof(val);
654 return 1;
655 case MA_OPT3_FILTERING:
656 if (strcasecmp(var, "Bilinear filtering") != 0) return 0;
657 currentConfig.scaling = atoi(val);
658 return 1;
659 case MA_OPT3_GAMMAA:
660 if (strcasecmp(var, "Gamma adjustment") != 0) return 0;
661 currentConfig.gamma = atoi(val);
662 return 1;
663 case MA_OPT3_BLACKLVL:
664 if (strcasecmp(var, "Black level") != 0) return 0;
665 currentConfig.gamma2 = atoi(val);
666 return 1;
667 case MA_OPT3_VSYNC:
668 if (strcasecmp(var, "Wait for vsync") != 0) return 0;
669 if (strcasecmp(val, "never") == 0) {
670 currentConfig.EmuOpt &= ~0x12000;
671 } else if (strcasecmp(val, "sometimes") == 0) {
672 currentConfig.EmuOpt |= 0x12000;
673 } else if (strcasecmp(val, "always") == 0) {
674 currentConfig.EmuOpt &= ~0x12000;
675 currentConfig.EmuOpt |= 0x02000;
676 } else
677 return 0;
678 return 1;
679
c51bd2fe 680 default:
3e85ebdd 681 lprintf("unhandled custom_read: %i\n", me->id);
c51bd2fe 682 return 0;
683 }
684}
685
686
8e708f92 687static unsigned int keys_encountered = 0;
688
960a8e27 689static void keys_parse(const char *var, const char *val, int binds[32], const char * const names[32])
367b6f1f 690{
8e708f92 691 int t, i;
367b6f1f 692 unsigned int player;
693
694 for (t = 0; t < 32; t++)
695 {
696 if (strcmp(names[t], var) == 0) break;
697 }
698 if (t == 32) {
699 lprintf("unhandled bind \"%s\"\n", var);
700 return;
701 }
702
8e708f92 703 if (binds == currentConfig.KeyBinds && !(keys_encountered & (1<<t))) { // hack
367b6f1f 704 binds[t] = 0;
705 keys_encountered |= 1<<t;
706 }
707 if (val[0] == 0)
708 return;
709 if (strncasecmp(val, "player", 6) == 0)
710 {
711 player = atoi(val + 6) - 1;
712 if (player > 1) goto fail;
713 for (i = 0; i < sizeof(me_ctrl_actions) / sizeof(me_ctrl_actions[0]); i++) {
714 if (strncasecmp(me_ctrl_actions[i].name, val + 8, strlen(val + 8)) == 0) {
715 binds[t] |= me_ctrl_actions[i].mask | (player<<16);
716 return;
717 }
718 }
719 }
720 for (i = 0; emuctrl_actions[i].name != NULL; i++) {
721 if (strncasecmp(emuctrl_actions[i].name, val, strlen(val)) == 0) {
722 binds[t] |= emuctrl_actions[i].mask;
723 return;
724 }
725 }
726
727fail:
728 lprintf("unhandled action \"%s\"\n", val);
729 return;
367b6f1f 730}
731
732
733#define try_joy_parse(num) { \
734 if (strncasecmp(var, "bind_joy"#num " ", 10) == 0) { \
735 keys_parse(var + 10, val, currentConfig.JoyBinds[num], joyKeyNames); \
736 return; \
737 } \
738}
739
c51bd2fe 740static void parse(const char *var, const char *val)
741{
742 menu_entry *me;
743 int t, i, tlen, tmp, ret = 0;
744
367b6f1f 745 if (strcasecmp(var, "LastUsedROM") == 0)
746 return; /* handled elsewhere */
747
67dfdf5f 748 if (strcasecmp(var, "Sound Volume") == 0) {
749 currentConfig.volume = atoi(val);
750 return;
751 }
752
367b6f1f 753 // key binds
754 if (strncasecmp(var, "bind ", 5) == 0) {
755 keys_parse(var + 5, val, currentConfig.KeyBinds, keyNames);
756 return;
757 }
758 try_joy_parse(0)
759 try_joy_parse(1)
760 try_joy_parse(2)
761 try_joy_parse(3)
762
c51bd2fe 763 for (t = 0; t < sizeof(cfg_opts) / sizeof(cfg_opts[0]) && ret == 0; t++)
764 {
765 me = cfg_opts[t];
766 tlen = *(cfg_opt_counts[t]);
767 for (i = 0; i < tlen && ret == 0; i++, me++)
768 {
769 if (!me->need_to_save) continue;
770 if (me->name != NULL) {
771 if (strcasecmp(var, me->name) != 0) continue; // surely not this one
772 if (me->beh == MB_ONOFF) {
773 tmp = atoi(val);
774 if (tmp) *(int *)me->var |= me->mask;
775 else *(int *)me->var &= ~me->mask;
776 return;
777 } else if (me->beh == MB_RANGE) {
778 tmp = atoi(val);
779 if (tmp < me->min) tmp = me->min;
780 if (tmp > me->max) tmp = me->max;
781 *(int *)me->var = tmp;
782 return;
783 }
784 }
785 ret = custom_read(me, var, val);
786 }
787 }
5d239ae7 788 if (!ret) lprintf("config_readsect: unhandled var: \"%s\"\n", var);
c51bd2fe 789}
790
791
367b6f1f 792int config_havesect(const char *fname, const char *section)
793{
794 FILE *f;
795 int ret;
796
797 f = fopen(fname, "r");
798 if (f == NULL) return 0;
799
800 ret = seek_sect(f, section);
801 fclose(f);
802 return ret;
803}
804
c51bd2fe 805int config_readsect(const char *fname, const char *section)
806{
7836e87c 807 char line[128], *var, *val;
367b6f1f 808 FILE *f;
7836e87c 809 int ret;
c51bd2fe 810
367b6f1f 811 f = fopen(fname, "r");
a5365695 812 if (f == NULL) return -1;
c51bd2fe 813
814 if (section != NULL)
815 {
816 ret = seek_sect(f, section);
817 if (!ret) {
3e85ebdd 818 lprintf("config_readsect: %s: missing section [%s]\n", fname, section);
c51bd2fe 819 fclose(f);
820 return -1;
821 }
822 }
823
8e708f92 824 keys_encountered = 0;
825
c51bd2fe 826 while (!feof(f))
827 {
7836e87c 828 ret = config_get_var_val(f, line, sizeof(line), &var, &val);
829 if (ret == 0) break;
830 if (ret == -1) continue;
c51bd2fe 831
832 parse(var, val);
833 }
834
835 fclose(f);
836 return 0;
837}
838
7836e87c 839#endif // _MSC_VER
840
841static char *mystrip(char *str)
842{
843 int i, len;
844
845 len = strlen(str);
846 for (i = 0; i < len; i++)
847 if (str[i] != ' ') break;
848 if (i > 0) memmove(str, str + i, len - i + 1);
849
850 len = strlen(str);
851 for (i = len - 1; i >= 0; i--)
852 if (str[i] != ' ') break;
853 str[i+1] = 0;
854
855 return str;
856}
857
858/* returns:
859 * 0 - EOF, end
860 * 1 - parsed ok
861 * -1 - failed to parse line
862 */
863int config_get_var_val(void *file, char *line, int lsize, char **rvar, char **rval)
864{
865 char *var, *val, *tmp;
866 FILE *f = file;
867 int len, i;
868
869 tmp = fgets(line, lsize, f);
870 if (tmp == NULL) return 0;
871
872 if (line[0] == '[') return 0; // other section
873
874 // strip comments, linefeed, spaces..
875 len = strlen(line);
876 for (i = 0; i < len; i++)
877 if (line[i] == '#' || line[i] == '\r' || line[i] == '\n') { line[i] = 0; break; }
878 mystrip(line);
879 len = strlen(line);
880 if (len <= 0) return -1;;
881
882 // get var and val
883 for (i = 0; i < len; i++)
884 if (line[i] == '=') break;
885 if (i >= len || strchr(&line[i+1], '=') != NULL) {
886 lprintf("config_readsect: can't parse: %s\n", line);
887 return -1;
888 }
889 line[i] = 0;
890 var = line;
891 val = &line[i+1];
892 mystrip(var);
893 mystrip(val);
894
895#ifndef _MSC_VER
896 if (strlen(var) == 0 || (strlen(val) == 0 && strncasecmp(var, "bind", 4) != 0)) {
897 lprintf("config_readsect: something's empty: \"%s\" = \"%s\"\n", var, val);
898 return -1;;
899 }
900#endif
901
902 *rvar = var;
903 *rval = val;
904 return 1;
905}
906