dxx-rebirth/common/main/cvar.cpp
2021-02-06 21:38:50 +01:00

191 lines
4.2 KiB
C++

/*
* This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>.
* It is copyright by its individual contributors, as recorded in the
* project's Git history. See COPYING.txt at the top level for license
* terms and a link to the Git history.
*
*/
/*
*
* Console variables
*
*/
#include <cstdarg>
#include <map>
#include <stdlib.h>
#include <physfs.h>
#include "cmd.h"
#include "console.h"
#include "cvar.h"
#include "dxxerror.h"
#include "strutil.h"
#include "u_mem.h"
#include "game.h"
#include "physfsx.h"
#include "dxxsconf.h"
#include "compiler-range_for.h"
#define CVAR_MAX_LENGTH 1024
/* The list of cvars */
typedef std::map<const char *, std::reference_wrapper<cvar_t>> cvar_list_type;
static cvar_list_type cvar_list;
const char *cvar_t::operator=(const char *s)
{
cvar_set_cvar(this, s);
return s;
}
int cvar_t::operator=(int i) { cvar_set_cvarf(this, "%d", i); return this->intval; }
void cvar_cmd_set(unsigned long argc, const char *const *const argv)
{
char buf[CVAR_MAX_LENGTH];
int ret;
if (argc == 2) {
cvar_t *ptr;
if ((ptr = cvar_find(argv[1])))
con_printf(CON_NORMAL, "%s: %s", ptr->name, ptr->string.c_str());
else
con_printf(CON_NORMAL, "set: variable %s not found", argv[1]);
return;
}
if (argc == 1) {
range_for (const auto &i, cvar_list)
con_printf(CON_NORMAL, "%s: %s", i.first, i.second.get().string.c_str());
return;
}
ret = snprintf(buf, sizeof(buf), "%s", argv[2]);
if (ret >= CVAR_MAX_LENGTH) {
con_printf(CON_CRITICAL, "set: value too long (max %d characters)", CVAR_MAX_LENGTH);
return;
}
size_t position = ret;
for (int i = 3; i < argc; i++) {
ret = snprintf(&buf[position], CVAR_MAX_LENGTH - position, " %s", argv[i]);
position += ret;
if (position >= CVAR_MAX_LENGTH)
{
con_printf(CON_CRITICAL, "set: value too long (max %d characters)", CVAR_MAX_LENGTH);
return;
}
}
cvar_set(argv[1], buf);
}
void cvar_init(void)
{
cmd_addcommand("set", cvar_cmd_set, "set <name> <value>\n" " set variable <name> equal to <value>\n"
"set <name>\n" " show value of <name>\n"
"set\n" " show value of all variables");
}
cvar_t *cvar_find(const char *cvar_name)
{
const auto i = cvar_list.find(cvar_name);
return i == cvar_list.end() ? nullptr : &i->second.get();
}
const char *cvar_complete(const char *text)
{
uint_fast32_t len = strlen(text);
if (!len)
return NULL;
range_for (const auto &i, cvar_list)
if (!d_strnicmp(text, i.first, len))
return i.first;
return NULL;
}
/* Register a cvar */
void cvar_registervariable (cvar_t &cvar)
{
cvar.value = fl2f(strtod(cvar.string.c_str(), NULL));
cvar.intval = static_cast<int>(strtol(cvar.string.c_str(), NULL, 10));
const auto i = cvar_list.insert(cvar_list_type::value_type(cvar.name, cvar));
if (!i.second)
{
Int3();
con_printf(CON_URGENT, "cvar %s already exists!", cvar.name);
return;
}
/* insert at end of list */
}
/* Set a CVar's value */
void cvar_set_cvar(cvar_t *cvar, const char *value)
{
if (!cvar)
return;
cvar->string = value;
cvar->value = fl2f(strtod(value, NULL));
cvar->intval = static_cast<int>(strtol(value, NULL, 10));
con_printf(CON_VERBOSE, "%s: %s", cvar->name, value);
}
void cvar_set_cvarf(cvar_t *cvar, const char *fmt, ...)
{
va_list arglist;
char buf[CVAR_MAX_LENGTH];
int n;
va_start (arglist, fmt);
n = vsnprintf(buf, sizeof(buf), fmt, arglist);
va_end (arglist);
if (n < 0 || n > CVAR_MAX_LENGTH) {
Int3();
con_printf(CON_CRITICAL, "error setting cvar %s", cvar->name);
return;
}
cvar_set_cvar(cvar, buf);
}
void cvar_set(const char *cvar_name, char *value)
{
cvar_t *cvar;
cvar = cvar_find(cvar_name);
if (!cvar) {
Int3();
con_printf(CON_NORMAL, "cvar %s not found", cvar_name);
return;
}
if (cvar->flags & CVAR_CHEAT && !cheats_enabled())
{
con_printf(CON_NORMAL, "cvar %s is cheat protected.", cvar_name);
return;
}
cvar_set_cvar(cvar, value);
}
/* Write archive cvars to file */
void cvar_write(PHYSFS_File *file)
{
range_for (const auto &i, cvar_list)
if (i.second.get().flags & CVAR_ARCHIVE)
PHYSFSX_printf(file, "%s=%s\n", i.first, i.second.get().string.c_str());
}