apple2ix/src/prefs.c

384 lines
10 KiB
C

/*
* Apple // emulator for *ix
*
* This software package is subject to the GNU General Public License
* version 3 or later (your choice) as published by the Free Software
* Foundation.
*
* Copyright 1994 Alexander Jean-Claude Bottema
* Copyright 1995 Stephen Lee
* Copyright 1997, 1998 Aaron Culliney
* Copyright 1998, 1999, 2000 Michael Deutschmann
* Copyright 2013-2015 Aaron Culliney
*
*/
#define _GNU_SOURCE
#include "common.h"
#define PRM_NONE 0
#define PRM_SPEED 1
#define PRM_ALTSPEED 101
#define PRM_MODE 2
#define PRM_DISK_PATH 3
#define PRM_HIRES_COLOR 4
#define PRM_VOLUME 5
#define PRM_JOY_INPUT 6
#define PRM_VIDEO_MODE 7
#define PRM_JOY_KPAD_CALIBRATE 11
#define PRM_ROM_PATH 12
#define PRM_CAPSLOCK 102
char system_path[PATH_MAX] = { 0 };
char disk_path[PATH_MAX] = { 0 };
#warning FIXME TODO : completely excise deprecated apple_mode stuff
int apple_mode = 2/*IIE_MODE*/;
a2_video_mode_t a2_video_mode = VIDEO_1X;
joystick_mode_t joy_mode = JOY_PCJOY;
static char *config_filename = NULL;
struct match_table
{
const char *tag;
int value;
};
static const struct match_table prefs_table[] =
{
{ "speed", PRM_SPEED },
{ "altspeed", PRM_ALTSPEED },
{ "mode", PRM_MODE },
{ "path", PRM_DISK_PATH },
{ "disk path", PRM_DISK_PATH },
{ "disk_path", PRM_DISK_PATH },
{ "path", PRM_DISK_PATH },
{ "color", PRM_HIRES_COLOR },
{ "video", PRM_VIDEO_MODE },
{ "volume", PRM_VOLUME },
{ "caps_lock", PRM_CAPSLOCK },
{ "caps lock", PRM_CAPSLOCK },
{ "joystick", PRM_JOY_INPUT },
{ "keypad joystick parms", PRM_JOY_KPAD_CALIBRATE },
{ "keypad_joystick_parms", PRM_JOY_KPAD_CALIBRATE },
{ "system path", PRM_ROM_PATH },
{ "system_path", PRM_ROM_PATH },
{ 0, PRM_NONE }
};
static const struct match_table color_table[] =
{
{ "black/white", COLOR_NONE },
/*{ "lazy color", LAZY_COLOR }, deprecated*/
{ "color", COLOR },
/*{ "lazy interpolated", LAZY_INTERP }, deprecated*/
{ "interpolated", COLOR_INTERP },
{ "off", 0 },
{ "on", COLOR },
{ 0, COLOR }
};
static const struct match_table video_table[] =
{
{ "1X", VIDEO_1X },
{ "2X", VIDEO_2X },
{ "Fullscreen", VIDEO_FULLSCREEN },
{ 0, VIDEO_1X }
};
static const struct match_table volume_table[] =
{
{ "0", 0 },
{ "1", 1 },
{ "2", 2 },
{ "3", 3 },
{ "4", 4 },
{ "5", 5 },
{ "6", 6 },
{ "7", 7 },
{ "8", 8 },
{ "9", 9 },
{ "10", 10 },
{ 0, 10 },
};
static const struct match_table capslock_table[] =
{
{ "0", 0 },
{ "1", 1 },
};
static const struct match_table joy_input_table[] =
{
{ "pc joystick", JOY_PCJOY },
#ifdef KEYPAD_JOYSTICK
{ "joy keypad", JOY_KPAD },
{ "joy_keypad", JOY_KPAD },
#endif
{ 0, JOY_PCJOY }
};
/* Find the number assigned to KEYWORD in a match table PARADIGM. If no match,
* then the value associated with the terminating entry is used as a
* default. */
static int match(const struct match_table *paradigm, const char *keyword)
{
while (paradigm->tag && strcasecmp(paradigm->tag, keyword))
{
paradigm++;
}
return paradigm->value;
}
/* Reverse match -- find a keyword associated with number KEY in
* PARADIGM. The first match is used -- synonym keywords appearing later
* in the table are not chosen.
*
* A null is returned for no match.
*/
static const char *reverse_match(const struct match_table *paradigm, int key)
{
while (paradigm->tag && key != paradigm->value)
{
paradigm++;
}
return paradigm->tag;
}
/* Eat leading and trailing whitespace of string X. The old string is
* overwritten and a new pointer is returned.
*/
static char * clean_string(char *x)
{
size_t y;
/* Leading white space */
while (isspace(*x))
{
x++;
}
/* Trailing white space */
y = strlen(x);
while (y && x[y--] == ' ')
{
}
x[y] = 0;
return x;
}
/* Load the configuration. Must be called *once* at start. */
void load_settings(void)
{
/* set system defaults before user defaults. */
strcpy(disk_path, "./disks");
strcpy(system_path, "./rom");
const char *apple2cfg = getenv("APPLE2IXCFG");
if (apple2cfg) {
config_filename = strdup(apple2cfg);
} else {
const char *homedir;
homedir = getenv("HOME");
config_filename = malloc(strlen(homedir) + 9);
strcpy(config_filename, homedir);
strcat(config_filename, "/.apple2");
/* config_filename is left allocated for convinence in
* save_settings */
}
{
char *buffer = 0;
size_t size = 0;
FILE *config_file = fopen(config_filename, "r");
if (config_file == NULL)
{
ERRLOG(
"Warning. Cannot open the .apple2 system defaults file.\n"
"Make sure it's readable in your home directory.");
return;
}
while (getline(&buffer, &size, config_file) != -1)
{
char *parameter;
char *argument;
/* Split line between parameter and argument */
parameter = buffer;
argument = strchr(buffer, '=');
argument[0] = 0;
argument++;
parameter = clean_string(parameter);
argument = clean_string(argument);
int main_match = match(prefs_table, parameter);
switch (main_match)
{
case PRM_NONE:
ERRLOG("Unrecognized config parameter `%s'", parameter);
break;
case PRM_SPEED:
case PRM_ALTSPEED:
{
double x = strtod(argument, NULL);
if (x > CPU_SCALE_FASTEST)
{
x = CPU_SCALE_FASTEST;
}
else if (x < CPU_SCALE_SLOWEST)
{
x = CPU_SCALE_SLOWEST;
}
if (main_match == PRM_SPEED)
{
cpu_scale_factor = x;
}
else
{
cpu_altscale_factor = x;
}
break;
}
case PRM_DISK_PATH:
strncpy(disk_path, argument, PATH_MAX-1);
disk_path[PATH_MAX-1] = '\0';
break;
case PRM_HIRES_COLOR:
color_mode = match(color_table, argument);
break;
case PRM_VIDEO_MODE:
a2_video_mode = match(video_table, argument);
break;
case PRM_VOLUME:
sound_volume = match(volume_table, argument);
break;
case PRM_CAPSLOCK:
caps_lock = match(capslock_table, argument) ? true : false;
break;
case PRM_JOY_INPUT:
joy_mode = match(joy_input_table, argument);
break;
#ifdef KEYPAD_JOYSTICK
case PRM_JOY_KPAD_CALIBRATE:
joy_step = strtol(argument, &argument, 10);
if (joy_step < 1)
{
joy_step = 1;
}
else if (joy_step > 255)
{
joy_step = 255;
}
joy_auto_recenter = strtol(argument, &argument, 10);
break;
#endif
case PRM_ROM_PATH:
strncpy(system_path, argument, PATH_MAX-1);
system_path[PATH_MAX-1] = '\0';
break;
}
}
FREE(buffer);
fclose(config_file);
}
}
/* Save the configuration */
bool save_settings(void)
{
FILE *config_file = NULL;
LOG("Saving preferences...");
#define PREFS_ERRPRINT() \
ERRLOG( \
"Cannot open the .apple2/apple2.cfg system defaults file for writing.\n" \
"Make sure it has rw permission in your home directory.")
#define ERROR_SUBMENU_H 9
#define ERROR_SUBMENU_W 40
#ifdef INTERFACE_CLASSIC
int ch = -1;
char submenu[ERROR_SUBMENU_H][ERROR_SUBMENU_W+1] =
//1. 5. 10. 15. 20. 25. 30. 35. 40.
{ "||||||||||||||||||||||||||||||||||||||||",
"| |",
"| |",
"| OOPS, could not open or write to the |",
"| .apple2/apple2.cfg file in your HOME |",
"| directory ... |",
"| |",
"| |",
"||||||||||||||||||||||||||||||||||||||||" };
#endif
config_file = fopen(config_filename, "w");
if (config_file == NULL)
{
PREFS_ERRPRINT();
#ifdef INTERFACE_CLASSIC
c_interface_print_submenu_centered(submenu[0], ERROR_SUBMENU_W, ERROR_SUBMENU_H);
while ((ch = c_mygetch(1)) == -1)
{
}
#endif
return false;
}
int err = 0;
err |= fprintf(config_file, "speed = %0.2lf\n", cpu_scale_factor);
err |= fprintf(config_file, "altspeed = %0.2lf\n", cpu_altscale_factor);
err |= fprintf(config_file, "disk path = %s\n", disk_path);
err |= fprintf(config_file, "color = %s\n", reverse_match(color_table, color_mode));
err |= fprintf(config_file, "video = %s\n", reverse_match(video_table, a2_video_mode));
err |= fprintf(config_file, "volume = %s\n", reverse_match(volume_table, sound_volume));
err |= fprintf(config_file, "caps lock = %s\n", reverse_match(capslock_table, (int)caps_lock));
err |= fprintf(config_file, "joystick = %s\n", reverse_match(joy_input_table, joy_mode));
err |= fprintf(config_file, "system path = %s\n", system_path);
#ifdef KEYPAD_JOYSTICK
err |= fprintf(config_file, "keypad joystick parms = %d %u\n", joy_step, (joy_auto_recenter ? 1 : 0));
#endif
if (err < 0) {
PREFS_ERRPRINT();
#ifdef INTERFACE_CLASSIC
c_interface_print_submenu_centered(submenu[0], ERROR_SUBMENU_W, ERROR_SUBMENU_H);
while ((ch = c_mygetch(1)) == -1) { }
#endif
return false;
}
fclose(config_file);
return true;
}