fceux/src/drivers/common/configSys.cpp

694 lines
16 KiB
C++

#include <iostream>
#include <fstream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "../../types.h"
#include "configSys.h"
std::string cfgFile = "fceux.cfg";
/**
* Add a given option. The option is specified as a short command
* line (-f), long command line (--foo), option name (Foo), its type
* (integer or string).
*/
int
Config::_addOption(char shortArg,
const std::string &longArg,
const std::string &name,
int type)
{
// make sure we have a valid type
if(type != INTEGER && type != STRING &&
type != DOUBLE && type != FUNCTION) {
return -1;
}
// check if the option already exists
if(_shortArgMap.find(shortArg) != _shortArgMap.end() ||
_longArgMap.find(longArg) != _longArgMap.end() ||
(type == INTEGER && _intOptMap.find(name) != _intOptMap.end()) ||
(type == STRING && _strOptMap.find(name) != _strOptMap.end()) ||
(type == DOUBLE && _dblOptMap.find(name) != _dblOptMap.end())) {
return -1;
}
// add the option
switch(type) {
case(STRING):
_strOptMap[name] = "";
break;
case(INTEGER):
_intOptMap[name] = 0;
break;
case(DOUBLE):
_dblOptMap[name] = 0.0;
break;
case(FUNCTION):
_fnOptMap[name] = NULL;
break;
default:
break;
}
_shortArgMap[shortArg] = name;
_longArgMap[longArg] = name;
return 0;
}
int
Config::_addOption(const std::string &longArg,
const std::string &name,
int type)
{
// make sure we have a valid type
if(type != STRING && type != INTEGER && type != DOUBLE) {
return -1;
}
// check if the option already exists
if(_longArgMap.find(longArg) != _longArgMap.end() ||
(type == STRING && _strOptMap.find(name) != _strOptMap.end()) ||
(type == INTEGER && _intOptMap.find(name) != _intOptMap.end()) ||
(type == DOUBLE && _dblOptMap.find(name) != _dblOptMap.end())) {
return -1;
}
// add the option
switch(type) {
case(STRING):
_strOptMap[name] = "";
break;
case(INTEGER):
_intOptMap[name] = 0;
break;
case(DOUBLE):
_dblOptMap[name] = 0.0;
break;
default:
break;
}
_longArgMap[longArg] = name;
return 0;
}
/**
* Add a given option and sets its default value. The option is
* specified as a short command line (-f), long command line (--foo),
* option name (Foo), its type (integer or string), and its default
* value.
*/
int
Config::addOption(char shortArg,
const std::string &longArg,
const std::string &name,
int defaultValue)
{
int error;
// add the option to the config system
error = _addOption(shortArg, longArg, name, INTEGER);
if(error) {
return error;
}
// set the option to the default value
error = setOption(name, defaultValue);
if(error) {
return error;
}
return 0;
}
/**
* Add a given option and sets its default value. The option is
* specified as a short command line (-f), long command line (--foo),
* option name (Foo), its type (integer or string), and its default
* value.
*/
int
Config::addOption(char shortArg,
const std::string &longArg,
const std::string &name,
double defaultValue)
{
int error;
// add the option to the config system
error = _addOption(shortArg, longArg, name, DOUBLE);
if(error) {
return error;
}
// set the option to the default value
error = setOption(name, defaultValue);
if(error) {
return error;
}
return 0;
}
/**
* Add a given option and sets its default value. The option is
* specified as a short command line (-f), long command line (--foo),
* option name (Foo), its type (integer or string), and its default
* value.
*/
int
Config::addOption(char shortArg,
const std::string &longArg,
const std::string &name,
const std::string &defaultValue)
{
int error;
// add the option to the config system
error = _addOption(shortArg, longArg, name, STRING);
if(error) {
return error;
}
// set the option to the default value
error = setOption(name, defaultValue);
if(error) {
return error;
}
return 0;
}
int
Config::addOption(char shortArg,
const std::string &longArg,
const std::string &name,
void (*defaultFn)(const std::string &))
{
int error;
// add the option to the config system
error = _addOption(shortArg, longArg, name, FUNCTION);
if(error) {
return error;
}
// set the option to the default value
error = setOption(name, defaultFn);
if(error) {
return error;
}
return 0;
}
int
Config::addOption(const std::string &longArg,
const std::string &name,
const std::string &defaultValue)
{
int error;
// add the option to the config system
error = _addOption(longArg, name, STRING);
if(error) {
return error;
}
// set the option to the default value
error = setOption(name, defaultValue);
if(error) {
return error;
}
return 0;
}
int
Config::addOption(const std::string &longArg,
const std::string &name,
int defaultValue)
{
int error;
// add the option to the config system
error = _addOption(longArg, name, INTEGER);
if(error) {
return error;
}
// set the option to the default value
error = setOption(name, defaultValue);
if(error) {
return error;
}
return 0;
}
int
Config::addOption(const std::string &longArg,
const std::string &name,
double defaultValue)
{
int error;
// add the option to the config system
error = _addOption(longArg, name, DOUBLE);
if(error) {
return error;
}
// set the option to the default value
error = setOption(name, defaultValue);
if(error) {
return error;
}
return 0;
}
int
Config::addOption(const std::string &name,
const std::string &defaultValue)
{
if(_strOptMap.find(name) != _strOptMap.end()) {
return -1;
}
// add the option
_strOptMap[name] = defaultValue;
return 0;
}
int
Config::addOption(const std::string &name,
int defaultValue)
{
if(_intOptMap.find(name) != _intOptMap.end()) {
return -1;
}
// add the option
_intOptMap[name] = defaultValue;
return 0;
}
int
Config::addOption(const std::string &name,
double defaultValue)
{
if(_dblOptMap.find(name) != _dblOptMap.end()) {
return -1;
}
// add the option
_dblOptMap[name] = defaultValue;
return 0;
}
/**
* Sets the specified option to the given integer value.
*/
int
Config::setOption(const std::string &name,
int value)
{
std::map<std::string, int>::iterator opt_i;
// confirm that the option exists
opt_i = _intOptMap.find(name);
if(opt_i == _intOptMap.end()) {
return -1;
}
// set the option
opt_i->second = value;
return 0;
}
/**
* Sets the specified option to the given integer value.
*/
int
Config::setOption(const std::string &name,
double value)
{
std::map<std::string, double>::iterator opt_i;
// confirm that the option exists
opt_i = _dblOptMap.find(name);
if(opt_i == _dblOptMap.end()) {
return -1;
}
// set the option
opt_i->second = value;
return 0;
}
/**
* Sets the specified option to the given string value.
*/
int
Config::setOption(const std::string &name,
const std::string &value)
{
std::map<std::string, std::string>::iterator opt_i;
// confirm that the option exists
opt_i = _strOptMap.find(name);
if(opt_i == _strOptMap.end()) {
return -1;
}
// set the option
opt_i->second = value;
return 0;
}
/**
* Sets the specified option to the given function.
*/
int
Config::setOption(const std::string &name,
void (*value)(const std::string &))
{
std::map<std::string, void (*)(const std::string &)>::iterator opt_i;
// confirm that the option exists
opt_i = _fnOptMap.find(name);
if(opt_i == _fnOptMap.end()) {
return -1;
}
// set the option
opt_i->second = value;
return 0;
}
int
Config::getOption(const std::string &name,
std::string *value)
{
std::map<std::string, std::string>::iterator opt_i;
// confirm that the option exists
opt_i = _strOptMap.find(name);
if(opt_i == _strOptMap.end()) {
return -1;
}
// get the option
(*value) = opt_i->second;
return 0;
}
int
Config::getOption(const std::string &name,
const char **value)
{
std::map<std::string, std::string>::iterator opt_i;
// confirm that the option exists
opt_i = _strOptMap.find(name);
if(opt_i == _strOptMap.end()) {
return -1;
}
// get the option
(*value) = opt_i->second.c_str();
return 0;
}
int
Config::getOption(const std::string &name,
int *value)
{
std::map<std::string, int>::iterator opt_i;
// confirm that the option exists
opt_i = _intOptMap.find(name);
if(opt_i == _intOptMap.end()) {
return -1;
}
// get the option
(*value) = opt_i->second;
return 0;
}
int
Config::getOption(const std::string &name,
double *value)
{
std::map<std::string, double>::iterator opt_i;
// confirm that the option exists
opt_i = _dblOptMap.find(name);
if(opt_i == _dblOptMap.end()) {
return -1;
}
// get the option
(*value) = opt_i->second;
return 0;
}
/**
* Parses the command line arguments. Short args are of the form -f
* <opt>, long args are of the form --foo <opt>. Returns < 0 on error,
* or the index of the rom file in argv.
*/
int
Config::_parseArgs(int argc,
char **argv)
{
int retval = 0;
std::map<std::string, std::string>::iterator long_i, str_i;
std::map<char, std::string>::iterator short_i;
std::map<std::string, int>::iterator int_i;
std::map<std::string, double>::iterator dbl_i;
std::map<std::string, void (*)(const std::string &)>::iterator fn_i;
std::string arg, opt, value;
for(int i = 1; i < argc; i++) {
arg = argv[i];
if(arg[0] != '-') {
// must be a rom name?
retval = i;
continue;
}
if(arg.size() < 2) {
// XXX invalid argument
return -1;
}
// parse the argument and get the option name
if(arg[1] == '-') {
// long arg
long_i = _longArgMap.find(arg.substr(2));
if(long_i == _longArgMap.end()) {
// XXX invalid argument
return -1;
}
opt = long_i->second;
} else {
// short arg
short_i = _shortArgMap.find(arg[1]);
if(short_i == _shortArgMap.end()) {
// XXX invalid argument
return -1;
}
opt = short_i->second;
}
// make sure we've got a value
if(i + 1 >= argc) {
// XXX missing value
return -1;
}
i++;
// now, find the appropriate option entry, and update it
str_i = _strOptMap.find(opt);
int_i = _intOptMap.find(opt);
dbl_i = _dblOptMap.find(opt);
fn_i = _fnOptMap.find(opt);
if(str_i != _strOptMap.end()) {
str_i->second = argv[i];
} else if(int_i != _intOptMap.end()) {
int_i->second = atol(argv[i]);
} else if(dbl_i != _dblOptMap.end()) {
dbl_i->second = atof(argv[i]);
} else if(fn_i != _fnOptMap.end()) {
(*(fn_i->second))(argv[i]);
} else {
// XXX invalid option? shouldn't happen
return -1;
}
}
// if we didn't get a rom-name, return error
return (retval) ? retval : -1;
}
/**
* Parses first the configuration file, and then overrides with any
* command-line options that were specified.
*/
int
Config::parse(int argc,
char **argv)
{
int error;
// read the config file
error = _load();
if(error) {
return error;
}
// parse the arguments
return _parseArgs(argc, argv);
}
/**
* Read each line of the config file and put the variables into the
* config maps. Valid configuration lines are of the form:
*
* <option name> = <option value>
*
* Lines beginning with # are ignored.
*/
char* Config::getConfigDirectory()
{
return strdup(_dir.c_str());
}
int
Config::_load()
{
signed int pos, eqPos;
std::fstream config;
std::map<std::string, int>::iterator int_i;
std::map<std::string, double>::iterator dbl_i;
std::map<std::string, std::string>::iterator str_i;
std::string configFile = _dir + "/" + cfgFile;
std::string line, name, value;
char buf[1024];
// set the exception handling to catch i/o errors
config.exceptions(std::fstream::badbit);
try {
// open the file for reading (create if it doesn't exist)
config.open(configFile.c_str(), std::ios::in | std::ios::out);
if(!config.is_open()) {
// XXX file couldn't be opened?
return 0;
}
while(!config.eof()) {
// read a line
config.getline(buf, 1024);
line = buf;
// check line validity
eqPos = line.find("=");
if(line[0] == '#') {
// skip this line
continue;
}
// get the name and value for the option
pos = line.find(" ");
name = line.substr(0, (pos > eqPos) ? eqPos : pos);
pos = line.find_first_not_of(" ", eqPos + 1);
if (pos == std::string::npos) value = "";
else value = line.substr(pos);
// check if the option exists, and if so, set it appropriately
str_i = _strOptMap.find(name);
dbl_i = _dblOptMap.find(name);
int_i = _intOptMap.find(name);
if(str_i != _strOptMap.end()) {
str_i->second = value;
} else if(int_i != _intOptMap.end()) {
int_i->second = atol(value.c_str());
} else if(dbl_i != _dblOptMap.end()) {
dbl_i->second = atof(value.c_str());
}
}
// close the file
config.close();
} catch(std::fstream::failure e) {
std::cerr << e.what() << std::endl;
return -1;
}
return 0;
}
/**
* Writes the configuration file with the current configuration settings.
*/
int
Config::save()
{
std::fstream config;
std::map<std::string, int>::iterator int_i;
std::map<std::string, double>::iterator dbl_i;
std::map<std::string, std::string>::iterator str_i;
std::string configFile = _dir + "/" + cfgFile;
char buf[1024];
// set the exception handling to catch i/o errors
config.exceptions(std::ios::failbit | std::ios::badbit);
try {
// open the file, truncate and for write
config.open(configFile.c_str(), std::ios::out | std::ios::trunc);
// write a warning
strcpy(buf, "# Auto-generated\n# SDL keycodes defined in /usr/include/SDL/SDL_keysym.h\n");
config.write(buf, strlen(buf));
// write each configuration setting
for(int_i = _intOptMap.begin(); int_i != _intOptMap.end(); int_i++) {
snprintf(buf, 1024, "%s = %d\n",
int_i->first.c_str(), int_i->second);
config.write(buf, strlen(buf));
}
for(dbl_i = _dblOptMap.begin(); dbl_i != _dblOptMap.end(); dbl_i++) {
snprintf(buf, 1024, "%s = %f\n",
dbl_i->first.c_str(), dbl_i->second);
config.write(buf, strlen(buf));
}
for(str_i = _strOptMap.begin(); str_i != _strOptMap.end(); str_i++) {
snprintf(buf, 1024, "%s = %s\n",
str_i->first.c_str(), str_i->second.c_str());
config.write(buf, strlen(buf));
}
// close the file
config.close();
} catch(std::fstream::failure e) {
std::cerr << e.what() << std::endl;
return -1;
}
return 0;
}