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