+ char cfgfile[MAXPATHLEN];
+ int i, ret = -1;
+ long size;
+ char *cfg;
+ FILE *f;
+
+ make_cfg_fname(cfgfile, sizeof(cfgfile), is_game);
+ f = fopen(cfgfile, "r");
+ if (f == NULL) {
+ printf("menu_load_config: failed to open: %s\n", cfgfile);
+ return -1;
+ }
+
+ fseek(f, 0, SEEK_END);
+ size = ftell(f);
+ if (size <= 0) {
+ printf("bad size %ld: %s\n", size, cfgfile);
+ goto fail;
+ }
+
+ cfg = malloc(size + 1);
+ if (cfg == NULL)
+ goto fail;
+
+ fseek(f, 0, SEEK_SET);
+ if (fread(cfg, 1, size, f) != size) {
+ printf("failed to read: %s\n", cfgfile);
+ goto fail_read;
+ }
+ cfg[size] = 0;
+
+ for (i = 0; i < ARRAY_SIZE(config_data); i++) {
+ char *tmp, *tmp2;
+ u32 val;
+
+ tmp = strstr(cfg, config_data[i].name);
+ if (tmp == NULL)
+ continue;
+ tmp += strlen(config_data[i].name);
+ if (strncmp(tmp, " = ", 3) != 0)
+ continue;
+ tmp += 3;
+
+ if (config_data[i].len == 0) {
+ parse_str_val(config_data[i].val, tmp);
+ continue;
+ }
+
+ tmp2 = NULL;
+ val = strtoul(tmp, &tmp2, 16);
+ if (tmp2 == NULL || tmp == tmp2)
+ continue; // parse failed
+
+ switch (config_data[i].len) {
+ case 1:
+ *(u8 *)config_data[i].val = val;
+ break;
+ case 2:
+ *(u16 *)config_data[i].val = val;
+ break;
+ case 4:
+ *(u32 *)config_data[i].val = val;
+ break;
+ default:
+ printf("menu_load_config: unhandled len %d for %s\n",
+ config_data[i].len, config_data[i].name);
+ break;
+ }
+ }
+
+ if (!is_game) {
+ char *tmp = strstr(cfg, "lastcdimg = ");
+ if (tmp != NULL) {
+ tmp += 12;
+ parse_str_val(last_selected_fname, tmp);
+ }
+ }
+
+ // sync plugins
+ for (i = gpu_plugsel = 0; gpu_plugins[i] != NULL; i++)
+ if (strcmp(Config.Gpu, gpu_plugins[i]) == 0)
+ { gpu_plugsel = i; break; }
+
+ for (i = spu_plugsel = 0; spu_plugins[i] != NULL; i++)
+ if (strcmp(Config.Spu, spu_plugins[i]) == 0)
+ { spu_plugsel = i; break; }
+
+ ret = 0;
+fail_read:
+ free(cfg);
+fail:
+ fclose(f);
+ return ret;