2016-07-26 07:22:47 +07:00
|
|
|
#include "precompiled.h"
|
|
|
|
|
2017-06-28 22:22:18 +04:00
|
|
|
MConfig::MConfig() : m_debuglevel(0), m_gamedll(nullptr), m_exec_cfg(nullptr), m_list(nullptr), m_filename(nullptr), m_clientmeta(FALSE)
|
2016-07-26 07:22:47 +07:00
|
|
|
{
|
2017-01-18 22:14:02 +07:00
|
|
|
set_directory();
|
2016-07-26 07:22:47 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize default values from the stored options struct. Has to happen
|
|
|
|
// _after_ constructor, so that all the fields are allocated (d'oh).
|
2016-07-26 15:18:32 +03:00
|
|
|
void MConfig::init(option_t* global_options)
|
2016-07-26 07:22:47 +07:00
|
|
|
{
|
2017-01-13 03:00:23 +03:00
|
|
|
m_list = global_options;
|
|
|
|
for (auto optp = m_list; optp->name; optp++)
|
2016-07-26 07:22:47 +07:00
|
|
|
set(optp, optp->init);
|
|
|
|
}
|
|
|
|
|
2017-05-09 19:31:09 +03:00
|
|
|
option_t* MConfig::find(const char* lookup) const
|
2016-07-26 07:22:47 +07:00
|
|
|
{
|
2017-05-09 19:31:09 +03:00
|
|
|
for (auto optp = m_list; optp->name; optp++) {
|
2017-01-18 22:14:02 +07:00
|
|
|
if (!Q_strcmp(optp->name, lookup)) {
|
2016-07-26 15:18:32 +03:00
|
|
|
return optp;
|
|
|
|
}
|
2016-07-26 23:31:47 +07:00
|
|
|
}
|
2017-05-09 19:31:09 +03:00
|
|
|
|
2017-05-05 19:36:56 +03:00
|
|
|
return nullptr;
|
2016-07-26 07:22:47 +07:00
|
|
|
}
|
|
|
|
|
2016-07-30 02:03:01 +03:00
|
|
|
bool MConfig::set(const char* key, const char* value) const
|
2016-07-26 07:22:47 +07:00
|
|
|
{
|
2016-07-26 15:18:32 +03:00
|
|
|
option_t* optp = find(key);
|
2016-07-26 07:22:47 +07:00
|
|
|
if (optp)
|
|
|
|
return set(optp, value);
|
2016-07-26 15:18:32 +03:00
|
|
|
|
2017-01-07 21:03:16 +03:00
|
|
|
return false;
|
2016-07-26 07:22:47 +07:00
|
|
|
}
|
|
|
|
|
2016-07-30 02:03:01 +03:00
|
|
|
bool MConfig::set(option_t* setp, const char* setstr)
|
2016-07-26 07:22:47 +07:00
|
|
|
{
|
2017-01-18 22:14:02 +07:00
|
|
|
char pathbuf[PATH_MAX];
|
2017-05-09 19:31:09 +03:00
|
|
|
int* optval = (int *)setp->dest;
|
|
|
|
char** optstr = (char **)setp->dest;
|
2016-07-26 15:18:32 +03:00
|
|
|
// cvar_t *optcvar = (cvar_t *) setp->dest;
|
|
|
|
// SETOPT_FN optcmd = (SETOPT_FN) setp->dest;
|
2016-07-26 07:22:47 +07:00
|
|
|
|
|
|
|
if (!setstr)
|
2016-07-30 02:03:01 +03:00
|
|
|
return true;
|
2016-07-26 07:22:47 +07:00
|
|
|
|
2017-05-09 19:31:09 +03:00
|
|
|
switch (setp->type) {
|
2016-07-26 07:22:47 +07:00
|
|
|
case CF_INT:
|
2017-05-09 19:31:09 +03:00
|
|
|
if (!isdigit(setstr[0])) {
|
2016-07-26 15:18:32 +03:00
|
|
|
META_ERROR("option '%s' invalid format '%s'", setp->name, setstr);
|
2017-01-07 21:03:16 +03:00
|
|
|
return false;
|
2016-07-26 07:22:47 +07:00
|
|
|
}
|
2016-07-26 23:31:47 +07:00
|
|
|
*optval = Q_atoi(setstr);
|
2017-01-09 01:30:23 +03:00
|
|
|
META_DEBUG(3, "set config int: %s = %d", setp->name, *optval);
|
2016-07-26 07:22:47 +07:00
|
|
|
break;
|
|
|
|
case CF_BOOL:
|
2017-05-09 19:31:09 +03:00
|
|
|
if (is_yes(setstr)) {
|
2016-07-26 15:18:32 +03:00
|
|
|
*optval = TRUE;
|
2016-07-26 07:22:47 +07:00
|
|
|
}
|
2017-05-09 19:31:09 +03:00
|
|
|
else if (is_no(setstr)) {
|
2016-07-26 15:18:32 +03:00
|
|
|
*optval = FALSE;
|
2016-07-26 07:22:47 +07:00
|
|
|
}
|
2017-05-09 19:31:09 +03:00
|
|
|
else {
|
2017-07-31 22:41:03 +07:00
|
|
|
META_ERROR("option '%s' invalid format '%s'", setp->name, setstr);
|
2017-01-07 21:03:16 +03:00
|
|
|
return false;
|
2016-07-26 07:22:47 +07:00
|
|
|
}
|
2017-01-09 02:44:49 +03:00
|
|
|
META_DEBUG(3, "set config bool: %s = %s", setp->name, *optval ? "true" : "false");
|
2016-07-26 07:22:47 +07:00
|
|
|
break;
|
|
|
|
case CF_STR:
|
2017-07-31 22:41:03 +07:00
|
|
|
if (*optstr) {
|
|
|
|
free(*optstr);
|
|
|
|
}
|
2016-07-26 23:31:47 +07:00
|
|
|
*optstr = Q_strdup(setstr);
|
2017-01-09 02:44:49 +03:00
|
|
|
META_DEBUG(3, "set config string: %s = %s", setp->name, *optstr);
|
2016-07-26 07:22:47 +07:00
|
|
|
break;
|
|
|
|
case CF_PATH:
|
2017-07-31 22:41:03 +07:00
|
|
|
if (*optstr) {
|
|
|
|
free(*optstr);
|
|
|
|
}
|
2016-07-26 07:22:47 +07:00
|
|
|
full_gamedir_path(setstr, pathbuf);
|
2016-07-26 23:31:47 +07:00
|
|
|
*optstr = Q_strdup(pathbuf);
|
2017-01-09 02:44:49 +03:00
|
|
|
META_DEBUG(3, "set config path: %s = %s", setp->name, *optstr);
|
2016-07-26 07:22:47 +07:00
|
|
|
break;
|
|
|
|
default:
|
2016-07-26 15:18:32 +03:00
|
|
|
META_ERROR("unrecognized config type '%d'", setp->type);
|
2017-01-07 21:03:16 +03:00
|
|
|
return false;
|
2016-07-26 07:22:47 +07:00
|
|
|
}
|
2016-07-26 23:31:47 +07:00
|
|
|
|
2016-07-30 02:03:01 +03:00
|
|
|
return true;
|
2016-07-26 07:22:47 +07:00
|
|
|
}
|
|
|
|
|
2016-07-30 02:03:01 +03:00
|
|
|
bool MConfig::load(const char* fn)
|
2016-07-26 07:22:47 +07:00
|
|
|
{
|
2017-01-18 22:14:02 +07:00
|
|
|
char loadfile[PATH_MAX];
|
2016-07-26 07:22:47 +07:00
|
|
|
char line[MAX_CONF_LEN];
|
|
|
|
|
|
|
|
// Make full pathname (from gamedir if relative, collapse "..",
|
|
|
|
// backslashes, etc).
|
|
|
|
full_gamedir_path(fn, loadfile);
|
|
|
|
|
2017-05-05 19:36:56 +03:00
|
|
|
FILE* fp = fopen(loadfile, "r");
|
2017-05-09 19:31:09 +03:00
|
|
|
if (!fp) {
|
2016-07-26 23:31:47 +07:00
|
|
|
META_ERROR("unable to open config file '%s': %s", loadfile, strerror(errno));
|
2017-01-07 21:03:16 +03:00
|
|
|
return false;
|
2016-07-26 07:22:47 +07:00
|
|
|
}
|
|
|
|
|
2017-01-09 02:44:49 +03:00
|
|
|
META_DEBUG(2, "Loading from config file: %s", loadfile);
|
2017-07-18 06:06:15 +07:00
|
|
|
for (int ln = 1; !feof(fp) && fgets(line, sizeof line, fp); ln++)
|
|
|
|
{
|
|
|
|
trimbuf(line);
|
|
|
|
|
|
|
|
if (line[0] == '\0' || line[0] == '#' || line[0] == ';' || !Q_strncmp(line, "//", 2))
|
2016-07-26 07:22:47 +07:00
|
|
|
continue;
|
2016-07-26 23:31:47 +07:00
|
|
|
|
2017-05-09 19:31:09 +03:00
|
|
|
char* optname = strtok(line, " \t\r\n");
|
|
|
|
if (!optname) {
|
2016-07-26 23:31:47 +07:00
|
|
|
META_ERROR("'%s' line %d: bad config format: missing option", loadfile, ln);
|
2016-07-26 07:22:47 +07:00
|
|
|
continue;
|
|
|
|
}
|
2017-05-09 19:31:09 +03:00
|
|
|
|
|
|
|
char *optval = strtok(nullptr, "\r\n");
|
|
|
|
if (!optval) {
|
2016-07-26 23:31:47 +07:00
|
|
|
META_ERROR("'%s' line %d: bad config format: missing value", loadfile, ln);
|
2016-07-26 07:22:47 +07:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-05-09 19:31:09 +03:00
|
|
|
auto optp = find(optname);
|
|
|
|
if (!optp) {
|
2016-07-26 23:31:47 +07:00
|
|
|
META_ERROR("'%s' line %d: unknown option name '%s'", loadfile, ln, optname);
|
2016-07-26 07:22:47 +07:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-05-09 19:31:09 +03:00
|
|
|
if (!set(optp, optval)) {
|
2016-07-26 23:31:47 +07:00
|
|
|
META_ERROR("'%s' line %d: unable to set option '%s' value '%s'", loadfile, ln, optname, optval);
|
2016-07-26 07:22:47 +07:00
|
|
|
}
|
|
|
|
}
|
2016-07-26 23:31:47 +07:00
|
|
|
|
2017-01-13 03:00:23 +03:00
|
|
|
m_filename = Q_strdup(loadfile);
|
2016-07-26 07:22:47 +07:00
|
|
|
fclose(fp);
|
2016-07-30 02:03:01 +03:00
|
|
|
return true;
|
2016-07-26 07:22:47 +07:00
|
|
|
}
|
|
|
|
|
2016-07-26 23:31:47 +07:00
|
|
|
void MConfig::show() const
|
2016-07-26 07:22:47 +07:00
|
|
|
{
|
2017-01-13 03:00:23 +03:00
|
|
|
META_CONS("Config options from localinfo and %s:", m_filename);
|
2016-07-26 07:22:47 +07:00
|
|
|
|
2017-05-09 19:31:09 +03:00
|
|
|
for (auto optp = m_list; optp->name; optp++) {
|
|
|
|
int* optval = (int *)optp->dest;
|
|
|
|
char** optstr = (char **)optp->dest;
|
2016-07-26 23:31:47 +07:00
|
|
|
|
2016-07-26 07:22:47 +07:00
|
|
|
// cvar_t *optcvar = (cvar_t *) optp->dest;
|
|
|
|
// SETOPT_FN optcmd = (SETOPT_FN) optp->dest;
|
2017-05-09 19:31:09 +03:00
|
|
|
switch (optp->type) {
|
2016-07-26 07:22:47 +07:00
|
|
|
case CF_INT:
|
2016-07-26 15:18:32 +03:00
|
|
|
printf(" %-20s\t%d\n", optp->name, *optval);
|
2016-07-26 07:22:47 +07:00
|
|
|
break;
|
|
|
|
case CF_BOOL:
|
2016-07-26 15:18:32 +03:00
|
|
|
printf(" %-20s\t%s\n", optp->name, *optval ? "true" : "false");
|
2016-07-26 07:22:47 +07:00
|
|
|
break;
|
|
|
|
case CF_STR:
|
|
|
|
case CF_PATH:
|
2016-07-26 15:18:32 +03:00
|
|
|
printf(" %-20s\t%s\n", optp->name, *optstr ? *optstr : "");
|
2016-07-26 07:22:47 +07:00
|
|
|
break;
|
|
|
|
case CF_NONE:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-01-18 22:14:02 +07:00
|
|
|
|
|
|
|
void MConfig::set_directory()
|
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
2017-05-05 19:36:56 +03:00
|
|
|
HMODULE hModule = nullptr;
|
2017-01-18 22:14:02 +07:00
|
|
|
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCTSTR)GiveFnptrsToDll, &hModule);
|
|
|
|
GetModuleFileName(hModule, m_directory, sizeof m_directory);
|
|
|
|
#else
|
|
|
|
Dl_info addrInfo;
|
2017-05-09 19:31:09 +03:00
|
|
|
if (dladdr((void *)GiveFnptrsToDll, &addrInfo)) {
|
2017-01-18 22:14:02 +07:00
|
|
|
Q_strncpy(m_directory, addrInfo.dli_fname, sizeof m_directory - 1);
|
|
|
|
m_directory[sizeof m_directory - 1] = '\0';
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-05-09 18:34:55 +03:00
|
|
|
normalize_path(m_directory);
|
2017-01-18 22:14:02 +07:00
|
|
|
|
|
|
|
// get directory
|
2017-05-09 19:31:09 +03:00
|
|
|
char* dir = Q_strrchr(m_directory, '/');
|
2017-01-18 22:14:02 +07:00
|
|
|
if (dir) {
|
|
|
|
*dir = '\0';
|
|
|
|
}
|
|
|
|
}
|