psp code updated for latest base, black level
[libpicofe.git] / common / config.c
CommitLineData
c51bd2fe 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"
3e85ebdd 11#include "lprintf.h"
c51bd2fe 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;
960a8e27 20#ifdef PSP
21extern menu_entry opt3_entries[];
22extern const int opt3_entry_count;
23#endif
c51bd2fe 24
960a8e27 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};
c51bd2fe 44
67dfdf5f 45#define NL "\r\n"
c51bd2fe 46
47
8e708f92 48static char *mystrip(char *str)
367b6f1f 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);
8e708f92 56
367b6f1f 57 len = strlen(str);
58 for (i = len - 1; i >= 0; i--)
59 if (str[i] != ' ') break;
60 str[i+1] = 0;
8e708f92 61
62 return str;
367b6f1f 63}
64
65
c51bd2fe 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
3e85ebdd 87static void custom_write(FILE *f, const menu_entry *me, int no_def)
c51bd2fe 88{
89 char *str, str24[24];
90
91 switch (me->id)
92 {
93 case MA_OPT_RENDERER:
dd5fd477 94 if (no_def && !((defaultConfig.s_PicoOpt^PicoOpt)&POPT_ALT_RENDERER) &&
c51bd2fe 95 !((defaultConfig.EmuOpt^currentConfig.EmuOpt)&0x80)) return;
dd5fd477 96 if (PicoOpt&POPT_ALT_RENDERER)
960a8e27 97 str =
98#ifndef PSP
99 "8bit "
100#endif
101 "fast";
c51bd2fe 102 else if (currentConfig.EmuOpt&0x80)
960a8e27 103 str =
104#ifndef PSP
105 "16bit "
106#endif
107 "accurate";
c51bd2fe 108 else
109 str = "8bit accurate";
110 fprintf(f, "Renderer = %s", str);
111 break;
112
113 case MA_OPT_SCALING:
3e85ebdd 114 if (no_def && defaultConfig.scaling == currentConfig.scaling) return;
960a8e27 115#ifdef __GP2X__
c51bd2fe 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;
960a8e27 121 case 1: str = "ON"; break;
c51bd2fe 122 }
123 fprintf(f, "Scaling = %s", str);
960a8e27 124#endif
c51bd2fe 125 break;
126 case MA_OPT_FRAMESKIP:
3e85ebdd 127 if (no_def && defaultConfig.Frameskip == currentConfig.Frameskip) return;
c51bd2fe 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:
dd5fd477 134 if (no_def && !((defaultConfig.s_PicoOpt^PicoOpt)&POPT_EN_STEREO) &&
c51bd2fe 135 defaultConfig.s_PsndRate == PsndRate) return;
dd5fd477 136 str = (PicoOpt&POPT_EN_STEREO)?"stereo":"mono";
c51bd2fe 137 fprintf(f, "Sound Quality = %i %s", PsndRate, str);
138 break;
139 case MA_OPT_REGION:
3e85ebdd 140 if (no_def && defaultConfig.s_PicoRegion == PicoRegionOverride &&
c51bd2fe 141 defaultConfig.s_PicoAutoRgnOrder == PicoAutoRgnOrder) return;
960a8e27 142 strncpy(str24, me_region_name(PicoRegionOverride, PicoAutoRgnOrder), 23); str24[23] = 0;
143 fprintf(f, "Region = %s", mystrip(str24));
c51bd2fe 144 break;
145 case MA_OPT_CONFIRM_STATES:
3e85ebdd 146 if (no_def && !((defaultConfig.EmuOpt^currentConfig.EmuOpt)&(5<<9))) return;
c51bd2fe 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:
3e85ebdd 156 if (no_def && defaultConfig.CPUclock == currentConfig.CPUclock) return;
960a8e27 157#ifdef __GP2X__
c51bd2fe 158 fprintf(f, "GP2X CPU clocks = %i", currentConfig.CPUclock);
960a8e27 159#elif defined(PSP)
160 fprintf(f, "PSP CPU clock = %i", currentConfig.CPUclock);
161#endif
c51bd2fe 162 break;
163 case MA_OPT2_GAMMA:
3e85ebdd 164 if (no_def && defaultConfig.gamma == currentConfig.gamma) return;
c51bd2fe 165 fprintf(f, "Gamma correction = %.3f", (double)currentConfig.gamma / 100.0);
166 break;
167 case MA_OPT2_SQUIDGEHACK:
3e85ebdd 168 if (no_def && !((defaultConfig.EmuOpt^currentConfig.EmuOpt)&0x0010)) return;
c51bd2fe 169 fprintf(f, "Squidgehack = %i", (currentConfig.EmuOpt&0x0010)>>4);
170 break;
171 case MA_CDOPT_READAHEAD:
3e85ebdd 172 if (no_def && defaultConfig.s_PicoCDBuffers == PicoCDBuffers) return;
c51bd2fe 173 sprintf(str24, "%i", PicoCDBuffers * 2);
174 fprintf(f, "ReadAhead buffer = %s", str24);
175 break;
960a8e27 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;
c51bd2fe 208
209 default:
3e85ebdd 210 lprintf("unhandled custom_write: %i\n", me->id);
c51bd2fe 211 return;
212 }
213 fprintf(f, NL);
214}
215
367b6f1f 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],
960a8e27 226 const int def_binds[32], const char * const names[32], int no_defaults)
367b6f1f 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
960a8e27 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
367b6f1f 245 for (i = 0; i < sizeof(me_ctrl_actions) / sizeof(me_ctrl_actions[0]); i++) {
246 if (me_ctrl_actions[i].mask & binds[t]) {
8e708f92 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));
367b6f1f 250 }
251 }
367b6f1f 252
8e708f92 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 }
367b6f1f 259 }
260}
261
262
3e85ebdd 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:
367b6f1f 274 case MA_OPT2_SVP_DYNAREC:
3e85ebdd 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}
c51bd2fe 298
299int config_writesect(const char *fname, const char *section)
300{
301 FILE *fo = NULL, *fn = NULL; // old and new
3e85ebdd 302 int no_defaults = 0; // avoid saving defaults
c51bd2fe 303 menu_entry *me;
304 int t, i, tlen, ret;
305 char line[128], *tmp;
306
307 if (section != NULL)
308 {
3e85ebdd 309 no_defaults = 1;
310
c51bd2fe 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)
3e85ebdd 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 }
c51bd2fe 389 }
390 }
367b6f1f 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
960a8e27 399#ifndef PSP
67dfdf5f 400 if (section == NULL)
401 fprintf(fn, "Sound Volume = %i" NL, currentConfig.volume);
960a8e27 402#endif
67dfdf5f 403
c51bd2fe 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
c51bd2fe 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
a5365695 432 if (strlen(lastRomFile) == 0) return -1;
c51bd2fe 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 }
367b6f1f 465 fprintf(f, "LastUsedROM = %s" NL, lastRomFile);
c51bd2fe 466 fclose(f);
467 return 0;
468}
469
367b6f1f 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
c51bd2fe 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;
960a8e27 516 if (strcasecmp(val, "8bit fast") == 0 || strcasecmp(val, "fast") == 0) {
dd5fd477 517 PicoOpt |= POPT_ALT_RENDERER;
c51bd2fe 518 }
960a8e27 519 else if (strcasecmp(val, "16bit accurate") == 0 || strcasecmp(val, "accurate") == 0) {
dd5fd477 520 PicoOpt &= ~POPT_ALT_RENDERER;
c51bd2fe 521 currentConfig.EmuOpt |= 0x80;
522 }
523 else if (strcasecmp(val, "8bit accurate") == 0) {
dd5fd477 524 PicoOpt &= ~POPT_ALT_RENDERER;
c51bd2fe 525 currentConfig.EmuOpt &= ~0x80;
526 }
527 else
528 return 0;
529 return 1;
530
531 case MA_OPT_SCALING:
960a8e27 532#ifdef __GP2X__
c51bd2fe 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;
960a8e27 545#else
546 return 0;
547#endif
c51bd2fe 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) {
dd5fd477 563 PicoOpt |= POPT_EN_STEREO;
c51bd2fe 564 } else if (strcasecmp(tmp, "mono") == 0) {
dd5fd477 565 PicoOpt &= ~POPT_EN_STEREO;
c51bd2fe 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;
3e85ebdd 577 for (i = 0; p < end && i < 3; i++)
578 {
579 while (*p == ' ') p++;
c51bd2fe 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 }
3e85ebdd 587 while (*p != ' ' && *p != 0) p++;
588 if (*p == 0) break;
c51bd2fe 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) {
367b6f1f 608 currentConfig.EmuOpt &= ~(5<<9);
c51bd2fe 609 } else if (strcasecmp(val, "writes") == 0) {
367b6f1f 610 currentConfig.EmuOpt &= ~(5<<9);
611 currentConfig.EmuOpt |= 1<<9;
c51bd2fe 612 } else if (strcasecmp(val, "loads") == 0) {
367b6f1f 613 currentConfig.EmuOpt &= ~(5<<9);
614 currentConfig.EmuOpt |= 4<<9;
c51bd2fe 615 } else if (strcasecmp(val, "both") == 0) {
367b6f1f 616 currentConfig.EmuOpt &= ~(5<<9);
617 currentConfig.EmuOpt |= 5<<9;
c51bd2fe 618 } else
619 return 0;
620 return 1;
621
622 case MA_OPT_CPU_CLOCKS:
960a8e27 623#ifdef __GP2X__
c51bd2fe 624 if (strcasecmp(var, "GP2X CPU clocks") != 0) return 0;
960a8e27 625#elif defined(PSP)
626 if (strcasecmp(var, "PSP CPU clock") != 0) return 0;
627#endif
c51bd2fe 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
960a8e27 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
c51bd2fe 686 default:
3e85ebdd 687 lprintf("unhandled custom_read: %i\n", me->id);
c51bd2fe 688 return 0;
689 }
690}
691
692
8e708f92 693static unsigned int keys_encountered = 0;
694
960a8e27 695static void keys_parse(const char *var, const char *val, int binds[32], const char * const names[32])
367b6f1f 696{
8e708f92 697 int t, i;
367b6f1f 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
8e708f92 709 if (binds == currentConfig.KeyBinds && !(keys_encountered & (1<<t))) { // hack
367b6f1f 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;
367b6f1f 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
c51bd2fe 746static void parse(const char *var, const char *val)
747{
748 menu_entry *me;
749 int t, i, tlen, tmp, ret = 0;
750
367b6f1f 751 if (strcasecmp(var, "LastUsedROM") == 0)
752 return; /* handled elsewhere */
753
67dfdf5f 754 if (strcasecmp(var, "Sound Volume") == 0) {
755 currentConfig.volume = atoi(val);
756 return;
757 }
758
367b6f1f 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
c51bd2fe 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 }
3e85ebdd 794 if (!ret) lprintf("config_readsect: unhandled var: %s\n", var);
c51bd2fe 795}
796
797
367b6f1f 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
c51bd2fe 812int config_readsect(const char *fname, const char *section)
813{
814 char line[128], *var, *val, *tmp;
c51bd2fe 815 int len, i, ret;
367b6f1f 816 FILE *f;
c51bd2fe 817
367b6f1f 818 f = fopen(fname, "r");
a5365695 819 if (f == NULL) return -1;
c51bd2fe 820
821 if (section != NULL)
822 {
823 ret = seek_sect(f, section);
824 if (!ret) {
3e85ebdd 825 lprintf("config_readsect: %s: missing section [%s]\n", fname, section);
c51bd2fe 826 fclose(f);
827 return -1;
828 }
829 }
830
8e708f92 831 keys_encountered = 0;
832
c51bd2fe 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) {
3e85ebdd 852 lprintf("config_readsect: can't parse: %s\n", line);
c51bd2fe 853 continue;
854 }
855 line[i] = 0;
856 var = line;
857 val = &line[i+1];
858 mystrip(var);
859 mystrip(val);
367b6f1f 860 if (strlen(var) == 0 || (strlen(val) == 0 && strncasecmp(var, "bind", 4) != 0)) {
3e85ebdd 861 lprintf("config_readsect: something's empty: \"%s\" = \"%s\"\n", var, val);
c51bd2fe 862 continue;
863 }
864
865 parse(var, val);
866 }
867
868 fclose(f);
869 return 0;
870}
871