aboutsummaryrefslogtreecommitdiff
path: root/saga/cvar.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'saga/cvar.cpp')
-rw-r--r--saga/cvar.cpp612
1 files changed, 612 insertions, 0 deletions
diff --git a/saga/cvar.cpp b/saga/cvar.cpp
new file mode 100644
index 0000000000..5f69faf3a9
--- /dev/null
+++ b/saga/cvar.cpp
@@ -0,0 +1,612 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004 The ScummVM project
+ *
+ * The ReInherit Engine is (C)2000-2003 by Daniel Balsom.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+/*
+ Description:
+
+ Configuration Variable Module
+
+ Notes:
+*/
+
+#include "reinherit.h"
+
+#include <limits.h>
+#include <stddef.h>
+
+/*
+ Uses the following modules:
+\*--------------------------------------------------------------------------*/
+#include "console_mod.h"
+
+/*
+ Begin module
+\*--------------------------------------------------------------------------*/
+#include "cvar_mod.h"
+#include "cvar.h"
+
+namespace Saga {
+
+R_CVAR *CVHashTbl[R_CVAR_HASHLEN];
+
+char *CVAR_ErrMsg[] = {
+
+ "No Error",
+ "Not implememented.",
+ "Memory allocation failed",
+ "Value overflowed while parsing",
+ "Invalid numeric constant",
+ "Value overflows destination type",
+ "Assignment of negative value to unsigned variable",
+ "Value outside of specified bounds",
+ "Invalid string literal",
+ "Invalid type for assignment",
+ "Variable is read-only",
+ "Not a valid function"
+};
+
+enum CVAR_Errors {
+
+ CVERR_NONE,
+ CVERR_NOTIMPL,
+ CVERR_MEM,
+ CVERR_PARSEOVERFLOW,
+ CVERR_INVALID,
+ CVERR_DESTOVERFLOW,
+ CVERR_SIGN,
+ CVERR_BOUND,
+ CVERR_STRING,
+ CVERR_TYPE,
+ CVERR_READONLY,
+ CVERR_NOTFUNC
+};
+
+static enum CVAR_Errors CVAR_ErrorState;
+
+int CVAR_GetError(char **err_str)
+/****************************************************************************\
+ Returns the appropriate cvar error string
+\****************************************************************************/
+{
+
+ *err_str = CVAR_ErrMsg[CVAR_ErrorState];
+
+ return CVAR_ErrorState;
+}
+
+int CVAR_Shutdown(void)
+/****************************************************************************\
+ Frees the cvar hash table
+\****************************************************************************/
+{
+
+ R_CVAR *walk_ptr;
+ R_CVAR *temp_ptr;
+ int i;
+
+ R_printf(R_STDOUT, "CVAR_Shutdown(): Deleting cvar hash table.\n");
+
+ for (i = 0; i < R_CVAR_HASHLEN; i++) {
+
+ for (walk_ptr = CVHashTbl[i]; walk_ptr; walk_ptr = temp_ptr) {
+
+ temp_ptr = walk_ptr->next;
+ free(walk_ptr);
+ }
+ }
+
+ return R_SUCCESS;
+}
+
+unsigned int CVAR_HashString(const char *str)
+/****************************************************************************\
+ Returns hash index for string 'str'.
+ Cannot fail.
+\****************************************************************************/
+{
+
+ unsigned int index;
+
+ for (index = 0; *str != '\0'; str++) {
+ index = *str + 31 * index;
+ }
+
+ return index % R_CVAR_HASHLEN;
+}
+
+int CVAR_Add(int index, R_CVAR * cvar)
+/****************************************************************************\
+ Adds a copy of the given cvar into the hash table.
+ Returns R_SUCCESS if cvar was added, R_MEM if allocation failed.
+\****************************************************************************/
+{
+
+ R_CVAR *new_cvar;
+ R_CVAR *temp_ptr;
+
+ new_cvar = (R_CVAR *)malloc(sizeof(R_CVAR));
+
+ if (new_cvar == NULL) {
+ CVAR_ErrorState = CVERR_MEM;
+ return R_MEM;
+ }
+
+ memcpy(new_cvar, cvar, sizeof(R_CVAR));
+
+ if (CVHashTbl[index] == NULL) {
+ CVHashTbl[index] = new_cvar;
+ new_cvar->next = NULL;
+ } else {
+ temp_ptr = CVHashTbl[index];
+ CVHashTbl[index] = new_cvar;
+ new_cvar->next = temp_ptr;
+ }
+
+ CVAR_ErrorState = CVERR_NONE;
+ return R_SUCCESS;
+}
+
+int CVAR_Exec(R_CVAR_P cvar_func, char *r_value)
+/****************************************************************************\
+ Attempts to execute the specified console function with the given argument
+ string.
+ Returns R_FAILURE if cvar_func is not a valid console function
+\****************************************************************************/
+{
+
+ int cf_argc = 0;
+ char **cf_argv = NULL;
+ int max_args;
+
+ if (cvar_func->type != R_CVAR_FUNC) {
+ CVAR_ErrorState = CVERR_NOTFUNC;
+ return R_FAILURE;
+ }
+
+ cf_argc = EXPR_GetArgs(r_value, &cf_argv);
+
+ if (cf_argc < cvar_func->t.func.min_args) {
+ CON_Print("Too few arguments to function.");
+ if (cf_argv)
+ free(cf_argv);
+ return R_FAILURE;
+ }
+
+ max_args = cvar_func->t.func.max_args;
+ if ((max_args > -1) && (cf_argc > max_args)) {
+ CON_Print("Too many arguments to function.");
+ if (cf_argv)
+ free(cf_argv);
+ return R_FAILURE;
+ }
+
+ /* Call function */
+ (cvar_func->t.func.func_p) (cf_argc, cf_argv);
+
+ if (cf_argv)
+ free(cf_argv);
+
+ return R_SUCCESS;
+}
+
+int CVAR_SetValue(R_CVAR_P cvar, char *r_value)
+/****************************************************************************\
+ Attempts to assign the value contained in the string 'r_value' to cvar.
+ Returns R_FAILURE if there was an error parsing 'r_value'
+\****************************************************************************/
+{
+
+ long int int_param;
+ unsigned long uint_param;
+
+ char *end_p;
+ ptrdiff_t scan_len;
+ int r_value_len;
+
+ r_value_len = strlen(r_value);
+
+ if (cvar->flags & R_CVAR_READONLY) {
+ CVAR_ErrorState = CVERR_READONLY;
+ return R_FAILURE;
+ }
+
+ switch (cvar->type) {
+
+ case R_CVAR_INT:
+
+ int_param = strtol(r_value, &end_p, 10);
+
+ if ((int_param == LONG_MIN) || (int_param == LONG_MAX)) {
+ CVAR_ErrorState = CVERR_PARSEOVERFLOW;
+ return R_FAILURE;
+ }
+
+ scan_len = end_p - r_value;
+
+ if (int_param == 0) {
+ if (!scan_len || r_value[scan_len - 1] != '0') {
+ /* strtol() returned 0, but string isn't "0". Invalid. */
+ CVAR_ErrorState = CVERR_INVALID;
+ return R_FAILURE;
+ }
+ }
+
+ if (scan_len != r_value_len) {
+ /* Entire string wasn't converted...Invalid */
+ CVAR_ErrorState = CVERR_INVALID;
+ return R_FAILURE;
+ }
+
+ if ((int_param < CV_INTMIN) || (int_param > CV_INTMAX)) {
+ /* Overflows destination type */
+ CVAR_ErrorState = CVERR_DESTOVERFLOW;
+ return R_FAILURE;
+ }
+
+ /* Ignore bounds if equal */
+ if (cvar->t.i.lbound != cvar->t.i.ubound) {
+
+ if ((int_param < cvar->t.i.lbound) ||
+ (int_param > cvar->t.i.ubound)) {
+ /* Value is outside of cvar bounds */
+ CVAR_ErrorState = CVERR_BOUND;
+ return R_FAILURE;
+ }
+ }
+
+ *(cvar->t.i.var_p) = (cv_int_t) int_param;
+
+#ifdef R_CVAR_TRACE
+ printf("Set cvar to value %ld.\n", int_param);
+#endif
+
+ break;
+
+ case R_CVAR_UINT:
+
+ if (*r_value == '-') {
+ CVAR_ErrorState = CVERR_SIGN;
+ return R_FAILURE;
+ }
+
+ uint_param = strtoul(r_value, &end_p, 10);
+
+ if (uint_param == ULONG_MAX) {
+ CVAR_ErrorState = CVERR_PARSEOVERFLOW;
+ return R_FAILURE;
+ }
+
+ scan_len = end_p - r_value;
+
+ if (uint_param == 0) {
+
+ if (!scan_len || r_value[scan_len - 1] != '0') {
+ /* strtol() returned 0, but string isn't "0". Invalid. */
+ CVAR_ErrorState = CVERR_INVALID;
+ return R_FAILURE;
+ }
+ }
+
+ if (scan_len != r_value_len) {
+ /* Entire string wasn't converted...Invalid */
+ CVAR_ErrorState = CVERR_INVALID;
+ return R_FAILURE;
+ }
+
+ if (uint_param > CV_UINTMAX) {
+ /* Overflows destination type */
+ CVAR_ErrorState = CVERR_DESTOVERFLOW;
+ return R_FAILURE;
+ }
+
+ /* Ignore bounds if equal */
+ if (cvar->t.ui.lbound != cvar->t.ui.ubound) {
+
+ if ((uint_param < cvar->t.ui.lbound) ||
+ (uint_param > cvar->t.ui.ubound)) {
+ /* Value is outside cvar bounds */
+ CVAR_ErrorState = CVERR_BOUND;
+ return R_FAILURE;
+ }
+ }
+
+ *(cvar->t.ui.var_p) = (cv_uint_t) uint_param;
+
+#ifdef R_CVAR_TRACE
+ printf("Set cvar to value %lu.\n", uint_param);
+#endif
+
+ break;
+
+ case R_CVAR_FLOAT:
+
+ CVAR_ErrorState = CVERR_NOTIMPL;
+ return R_FAILURE;
+ break;
+
+ case R_CVAR_STRING:
+
+ if (strrchr(r_value, '\"') != NULL) {
+ CVAR_ErrorState = CVERR_STRING;
+ return R_FAILURE;
+ }
+
+ strncpy(cvar->t.s.var_str, r_value, cvar->t.s.ubound);
+ if (cvar->t.s.ubound < r_value_len) {
+ cvar->t.s.var_str[cvar->t.s.ubound] = 0;
+ }
+#ifdef R_CVAR_TRACE
+ printf("Set cvar to value \"%s\".\n", cvar->t.s.var_str);
+#endif
+
+ break;
+
+ default:
+
+ CVAR_ErrorState = CVERR_TYPE;
+ return R_FAILURE;
+ break;
+ }
+
+ CVAR_ErrorState = CVERR_NONE;
+ return R_SUCCESS;
+}
+
+R_CVAR_P CVAR_Find(const char *var_str)
+/****************************************************************************\
+ Given a cvar name this function returns a pointer to the appropriate
+ cvar structure or NULL if no match was found.
+\****************************************************************************/
+{
+
+ R_CVAR *walk_ptr;
+ int hash;
+
+ hash = CVAR_HashString(var_str);
+
+#ifdef R_CVAR_TRACE
+ printf("Performing lookup on hash bucket %d.\n", hash);
+#endif
+
+ walk_ptr = CVHashTbl[hash];
+
+ while (walk_ptr != NULL) {
+
+ if (strcmp(var_str, walk_ptr->name) == 0) {
+ return walk_ptr;
+ }
+
+ walk_ptr = walk_ptr->next;
+ }
+
+ return NULL;
+}
+
+int CVAR_IsFunc(R_CVAR_P cvar_func)
+{
+
+ if (cvar_func->type == R_CVAR_FUNC)
+ return 1;
+ else
+ return 0;
+}
+
+int
+CVAR_RegisterFunc(cv_func_t func,
+ const char *func_name,
+ const char *func_argstr, uint flags, int min_args, int max_args)
+/****************************************************************************\
+ Registers a console function 'cvar'
+ (could think of a better place to put these...?)
+\****************************************************************************/
+{
+
+ R_CVAR new_cvar;
+ int hash;
+
+ new_cvar.name = func_name;
+ new_cvar.type = R_CVAR_FUNC;
+ new_cvar.section = NULL;
+ new_cvar.flags = flags;
+
+ new_cvar.t.func.func_p = func;
+ new_cvar.t.func.func_argstr = func_argstr;
+ new_cvar.t.func.min_args = min_args;
+ new_cvar.t.func.max_args = max_args;
+ hash = CVAR_HashString(func_name);
+
+#ifdef R_CVAR_TRACE
+ printf("Added FUNC cvar to hash bucket %d.\n", hash);
+#endif
+
+ return CVAR_Add(hash, &new_cvar);
+}
+
+int
+CVAR_Register_I(cv_int_t * var_p,
+ const char *var_name,
+ const char *section, uint flags, cv_int_t lbound, cv_int_t ubound)
+/****************************************************************************\
+ Registers an integer type cvar.
+\****************************************************************************/
+{
+
+ R_CVAR new_cvar;
+ int hash;
+
+ new_cvar.name = var_name;
+ new_cvar.type = R_CVAR_INT;
+ new_cvar.section = section;
+ new_cvar.flags = flags;
+
+ new_cvar.t.i.var_p = var_p;
+
+ new_cvar.t.i.lbound = lbound;
+ new_cvar.t.i.ubound = ubound;
+
+ hash = CVAR_HashString(var_name);
+
+#ifdef R_CVAR_TRACE
+ printf("Added INT cvar to hash bucket %d.\n", hash);
+#endif
+
+ return CVAR_Add(hash, &new_cvar);
+}
+
+int
+CVAR_Register_UI(cv_uint_t * var_p,
+ const char *var_name,
+ const char *section, uint flags, cv_uint_t lbound, cv_uint_t ubound)
+/****************************************************************************\
+ Registers an unsigned integer type cvar.
+\****************************************************************************/
+{
+
+ R_CVAR new_cvar;
+ int hash;
+
+ new_cvar.name = var_name;
+ new_cvar.type = R_CVAR_UINT;
+ new_cvar.section = section;
+ new_cvar.flags = flags;
+
+ new_cvar.t.ui.var_p = var_p;
+
+ new_cvar.t.ui.lbound = lbound;
+ new_cvar.t.ui.ubound = ubound;
+
+ hash = CVAR_HashString(var_name);
+
+#ifdef R_CVAR_TRACE
+ printf("Added UNSIGNED INT ccvar to hash bucket %d.\n", hash);
+#endif
+
+ return CVAR_Add(hash, &new_cvar);
+}
+
+int
+CVAR_Register_F(cv_float_t * var_p,
+ const char *var_name,
+ const char *section, uint flags, cv_float_t lbound, cv_float_t ubound)
+/****************************************************************************\
+ Registers a floating point type cvar.
+\****************************************************************************/
+{
+
+ R_CVAR new_cvar;
+ int hash;
+
+ new_cvar.name = var_name;
+ new_cvar.type = R_CVAR_FLOAT;
+ new_cvar.section = section;
+ new_cvar.flags = flags;
+
+ new_cvar.t.f.var_p = var_p;
+
+ new_cvar.t.f.lbound = lbound;
+ new_cvar.t.f.ubound = ubound;
+
+ hash = CVAR_HashString(var_name);
+
+#ifdef R_CVAR_TRACE
+ printf("Added FLOAT cvar to hash bucket %d.\n", hash);
+#endif
+
+ return CVAR_Add(hash, &new_cvar);
+}
+
+int
+CVAR_Register_S(cv_char_t * var_str,
+ const char *var_name, const char *section, uint flags, int ubound)
+/****************************************************************************\
+ Registers a string type cvar. Storage must be provided in var_p for 'ubound'
+ characters plus 1 for NUL char.
+\****************************************************************************/
+{
+
+ R_CVAR new_cvar;
+ int hash;
+
+ new_cvar.name = var_name;
+ new_cvar.type = R_CVAR_STRING;
+ new_cvar.section = section;
+ new_cvar.flags = flags;
+
+ new_cvar.t.s.var_str = var_str;
+ new_cvar.t.s.ubound = ubound;
+
+ hash = CVAR_HashString(var_name);
+
+#ifdef R_CVAR_TRACE
+ printf("Added UNSIGNED INT var to hash bucket %d.\n", hash);
+#endif
+
+ return CVAR_Add(hash, &new_cvar);
+}
+
+int CVAR_Print(R_CVAR_P con_cvar)
+/****************************************************************************\
+ Displays the value and type of the given cvar to the console.
+\****************************************************************************/
+{
+
+ switch (con_cvar->type) {
+
+ case R_CVAR_INT:
+ CON_Print("\"%s\"(i) = %d",
+ con_cvar->name, *(con_cvar->t.i.var_p));
+ break;
+
+ case R_CVAR_UINT:
+ CON_Print("\"%s\"(ui) = %u",
+ con_cvar->name, *(con_cvar->t.ui.var_p));
+ break;
+
+ case R_CVAR_FLOAT:
+ CON_Print("\"%s\"(ui) = %f",
+ con_cvar->name, *(con_cvar->t.f.var_p));
+ break;
+
+ case R_CVAR_STRING:
+ CON_Print("\"%s\"(s) = \"%s\"", con_cvar->name,
+ con_cvar->t.s.var_str);
+ break;
+
+ case R_CVAR_FUNC:
+ if (con_cvar->t.func.func_argstr) {
+ CON_Print("\"%s\"(func) Args: %s", con_cvar->name,
+ con_cvar->t.func.func_argstr);
+ } else {
+ CON_Print("\"%s\"(func) No arguments.",
+ con_cvar->name);
+ }
+ break;
+
+ default:
+ CON_Print("Invalid variable type.\n");
+ break;
+ }
+
+ return R_SUCCESS;
+}
+
+} // End of namespace Saga