diff -uNr quake3/cgame/cg_consolecmds.c fi/cgame/cg_consolecmds.c --- quake3/cgame/cg_consolecmds.c Sun Jan 14 16:45:10 2001 +++ fi/cgame/cg_consolecmds.c Tue Aug 7 22:32:48 2001 @@ -478,6 +478,10 @@ const char *cmd; int i; + switch (QSH_trap()) { + case 0: return qfalse; break; + case 1: return qtrue; break; + } cmd = CG_Argv(0); for ( i = 0 ; i < sizeof( commands ) / sizeof( commands[0] ) ; i++ ) { diff -uNr quake3/cgame/cg_hash.c fi/cgame/cg_hash.c --- quake3/cgame/cg_hash.c Wed Dec 31 16:00:00 1969 +++ fi/cgame/cg_hash.c Tue Aug 7 21:24:34 2001 @@ -0,0 +1,55 @@ +/* + The following hash function is a modified version of the one found in + kazlib-1.19, and qualifies as a `derivative work'. + Copyright notice for kazlib-1.19 follows, which applies *only* to the hash + function `hash_func'. +*/ +/* + * Hash Table Data Type + * Copyright (C) 1997 Kaz Kylheku + * + * Free Software License: + * + * All rights are reserved by the author, with the following exceptions: + * Permission is granted to freely reproduce and distribute this software, + * possibly in exchange for a fee, provided that this copyright notice appears + * intact. Permission is also granted to adapt this software to produce + * derivative works, as long as the modified versions carry this copyright + * notice and additional notices stating that the work has been modified. + * This source code may be translated into executable form and incorporated + * into proprietary software; there is no requirement for such software to + * contain a copyright notice related to this source. + * + */ +unsigned int +hash_func (const char *key) +{ + static unsigned long randbox[] = { + 0x49848f1bU, 0xe6255dbaU, 0x36da5bdcU, 0x47bf94e9U, + 0x8cbcce22U, 0x559fc06aU, 0xd268f536U, 0xe10af79aU, + 0xc1af4d69U, 0x1d2917b5U, 0xec4c304dU, 0x9ee5016cU, + 0x69232f74U, 0xfead7bb3U, 0xe9089ab6U, 0xf012f6aeU, + }; + + const char *str; + unsigned int acc = 0; + + str = key; + while (*str) { + acc ^= randbox[(*str + acc) & 0xf]; + acc = (acc << 1) | (acc >> 31); + acc &= 0xffffffffU; + acc ^= randbox[((*str++ >> 4) + acc) & 0xf]; + acc = (acc << 2) | (acc >> 30); + acc &= 0xffffffffU; + } + /* Normalize along -INF to +INF */ + return (int)(acc - 0x80000000); +} + + +unsigned int +QSH_hash (const char *key) +{ + return hash_func(key); +} diff -uNr quake3/cgame/cg_qsh2.c fi/cgame/cg_qsh2.c --- quake3/cgame/cg_qsh2.c Wed Dec 31 16:00:00 1969 +++ fi/cgame/cg_qsh2.c Tue Aug 7 23:57:13 2001 @@ -0,0 +1,543 @@ +/* + Quake III Shell Interpreter Take 2 + + by PhaethonH +*/ + +#define QSH_VERSION "0.01" +#define MAGIC_QSH 0x27610286 + +#define debug CG_Printf + + + +#include "cg_local.h" + + +#define SUBST_MARKER '$' + + + +enum { + QSH_OUTPUT_SIZE = 1024, +}; + +struct qsh_s { + int magic; + int shift; /* if any shift. */ + int numintern; /* number of internal commands. */ + char qerr[QSH_OUTPUT_SIZE]; + char qout[QSH_OUTPUT_SIZE]; +}; + +typedef struct qsh_s qsh_t; + + + + +struct qshcmd_s { + unsigned int hash; + int (*func)(char*,char*,char*); + char *name; +}; + +typedef struct qshcmd_s qshcmd_t; + + + + + + +qsh_t qsh; + + + + + + + +extern unsigned int QSH_hash(const char*); + +#define PROTOTYPE_SUBST(p) int QSH_##p (char *, char*, char, int) +/* Then PROTOTYPE_SUBST(foo) => int QSH_foo (char *, char *, char, int) */ + +PROTOTYPE_SUBST(substitution); +PROTOTYPE_SUBST(param_subst); +PROTOTYPE_SUBST(pos_subst); +PROTOTYPE_SUBST(cmd_subst); +PROTOTYPE_SUBST(var_subst); +PROTOTYPE_SUBST(arith_subst); + + + + + + +int +QSH_argc () +{ + int retval; + retval = trap_Argc() - qsh.shift; + return retval; +} + +int +QSH_argv (char *dest, int n, int destsize) +{ + int retval; + n -= qsh.shift; + trap_Argv(n, dest, destsize); + retval = strlen(dest); + return retval; +} + +void +QSH_print (char *format, ...) +{ + va_list argptr; + + va_start(argptr, format); + Q_strcat(qsh.qout, sizeof(qsh.qout), va(format, argptr)); + va_end(argptr); +} + +void +QSH_error (char *format, ...) +{ + va_list argptr; + + va_start(argptr, format); + Q_strcat(qsh.qerr, sizeof(qsh.qerr), va(format, argptr)); + va_end(argptr); +} + + +int +QSH_isdigit (char c) +{ + return (('0' <= c) && (c <= '9')); +} + + +int +QSH_isid (char c) +{ + return ( (('a' <= c) && (c <= 'z')) + || (('A' <= c) && (c <= 'Z')) + || (c == '_') + ); +} + + + + + + + + +/* + Special variables that are always in-scope. +*/ +int +QSH_try_var_special (char *dest, char *name, int destsize) +{ + if (0 == Q_stricmp(name, "health")) + { + Q_strncpyz(dest, va("%d", cg.snap->ps.stats[STAT_HEALTH]), destsize); + } + else if (0 == Q_stricmp(name, "armor")) + { + Q_strncpyz(dest, va("%d", cg.snap->ps.stats[STAT_ARMOR]), destsize); + } + else if (0 == Q_stricmp(name, "location")) + { + Q_strncpyz(dest, CG_ConfigString(CS_LOCATIONS + cgs.clientinfo[cg.clientNum].location), destsize); + } + else if (0 == Q_stricmp(name, "weapon")) + { + Q_strncpyz(dest, cg_weapons[cg.snap->ps.weapon].item->pickup_name, destsize); + } + else if (0 == Q_stricmp(name, "ammo")) + { + Q_strncpyz(dest, va("%d", cg.snap->ps.ammo[cg.snap->ps.weapon]), destsize); + } + + return strlen(dest); +} + + +/* + Variables in the local stack frame. +*/ +int +QSH_try_var_local (char *dest, char *name, int destsize) +{ + return 0; +} + + +/* + Cvar variables. + Cvars in Q3SH shadow the role of environment variables in bash. +*/ +int +QSH_try_var_console (char *dest, char *name, int destsize) +{ + trap_Cvar_VariableStringBuffer(name, dest, destsize); + return strlen(dest); +} + + + +/* + Given a variable name `name', copy the value of the variable to `dest', which has size constraint `destsize' bytes. + + Returns length of value. -1 if existence of variable could not be verified. +*/ +int +QSH_copyvarbyname (char *dest, char *name, int destsize) +{ + int i; + + /* Obtuse abuse of shortcuts. But it works, dammit. */ + /* Change the order of functions to change precedence of scopes. */ + /* e.g. put QSH_try_var_console to put cvars as top precedence. */ + i = + QSH_try_var_special (dest, name, destsize) + || + QSH_try_var_local (dest, name, destsize) + || + QSH_try_var_console (dest, name, destsize) + ; + + return i; +} + + + + + +/* + Scan the string `src' for any required substitution. + The evaluated result is placed into `dest', with size limitation `destsize'. + + Returns number of characters scanned in `src' before returning. +*/ +int +QSH_substitution (char *dest, char *src, char terminator, int destsize) +{ + int i, len; + + len = 0; + i = 0; + while ((src[i]) && (src[i] != terminator)) + { + if (src[i] == SUBST_MARKER) + { +//debug("qsh_subst: hit subst marker\n"); + i++; + i += QSH_param_subst (dest + len, src + i, 0, destsize - len); + len += strlen(dest + len); /* dangerous? */ + } + else + { + if (len < destsize - 1) + { + dest[len++] = src[i]; + dest[len] = 0; + } + } + i++; /* Next character. */ + } + return i; +} + + +/* + We hit a substitution marker, now we're here. + We can go to positional, variable, or command expansion from here. + We reach arithmetic substitution by jumping to command first. +*/ +int +QSH_param_subst (char *dest, char *src, char terminator, int destsize) +{ + int i, len, b; + char buf[256]; + + i = 0; + len = 0; + +//debug("qsh_param_subst: start, term = [%d]\n", terminator); + if (terminator) + { + b = 0; + while ((src[i] != terminator) && (b < sizeof(buf))) + { + buf[b++] = src[i++]; + } + buf[b] = 0; +//debug("qsh_param_subst: evaling [%s]\n", buf); + QSH_copyvarbyname(dest + len, buf, destsize - len); + len += strlen(dest + len); + return i; + } + + if (src[i] == '{') + { +//debug("qsh_param_subst: going param subst on {\n"); + i++; + i += QSH_param_subst (dest + len, src + i, '}', destsize - len); + len += strlen(dest + len); + } + else if (src[i] == '(') + { +//debug("qsh_param_subst: going cmd subst on (\n"); + i++; + i += QSH_cmd_subst (dest + len, src + i, ')', destsize - len); + len += strlen(dest + len); + } + else if (QSH_isdigit(src[i]) || (src[i] == '*') || (src[i] == '@')) + /* A digit, a '*', or a '@' */ + { +//debug("qsh_param_subst: going pos subst on %c\n", src[i]); + i += QSH_pos_subst (dest + len, src + i, 0, destsize - len); + len += strlen(dest + len); + } + else //if (QSH_isid(src[i])) + { +//debug("qsh_param_subst: going var subst on %c\n", src[i]); + i += QSH_var_subst (dest + len, src + i, 0, destsize - len); + len += strlen(dest + len); + } + + return i; +} + + +int +QSH_pos_subst (char *dest, char *src, char terminator, int destsize) +{ + int i, len, n; + + i = 0; + len = 0; + n = 0; + if (src[i] == '@') + { + /* All positional parameters attached. */ + for (n = 1; n < QSH_argc(); n++) + { + Q_strcat(dest, destsize, " "); + len = strlen(dest); + len += QSH_argv(dest + len, n, destsize - len); + } + } + else if (src[i] == '*') + { + /* All positional parameters as one word. */ + Q_strcat(dest, destsize, "\""); + for (n = 1; n < QSH_argc(); n++) + { + QSH_argv(dest + len, n, destsize - len); + Q_strcat(dest, destsize, " "); + len = strlen(dest); + } + dest[len - 1] = '"'; + } + else + { + n = (*src - '0'); + trap_Argv(n, dest + len, destsize - len); + len += strlen(dest + len); + } + + i = 1; + return i; +} + + +int +QSH_var_subst (char *dest, char *src, char terminator, int destsize) +{ + int i, len, b; + char buf[256]; + + i = 0; + len = 0; + b = 0; + + while (src[i] && (src[i] != terminator) && (QSH_isid(src[i]))) + { + buf[b++] = src[i++]; + } + buf[b] = 0; + i--; /* since `i' is now on a delimiter, and we don't actually consume that. */ +//debug("var name = [%s]\n", buf); + + len = QSH_copyvarbyname(dest, buf, destsize); +//debug("[%s] = [%s]\n", buf, dest); + return i; +} + + +int +QSH_cmd_subst (char *dest, char *src, char terminator, int destsize) +{ + int i; + int len; + + i = 0; + len = 0; + if (src[i] == '(') + { + i++; + i += QSH_arith_subst(dest + len, src + i, ')', destsize - len); + len += strlen(dest + len); + } + else + { + 0; + } + return i; +} + + +int +QSH_arith_subst (char *dest, char *src, char terminator, int destsize) +{ + return 0; +} + + + + +int +QSH_eval (char *qout, char *qerr, char *qin) +{ + char args[1024]; + char buf[1024]; + +//debug("qsh_eval: start\n"); + trap_Args(args, sizeof(args)); +//debug("qsh_eval: subbing on [%s]\n", args); + QSH_substitution(buf, args, 0, sizeof(buf)); +//debug("qsh_eval: subbed = [%s]\n", buf); + trap_SendConsoleCommand(buf); +//debug("qsh_eval: end\n"); + return 1; +} + + +int +QSH_ver (char *quot, char *qerr, char *qin) +{ + QSH_print ("Q3SH v" QSH_VERSION "\n"); + return 1; +} + + + + + + + + + + +qshcmd_t qshcmds[] = { + { 0, QSH_eval, "eval" }, + { 0, QSH_ver, "ver" }, + { 0, 0, 0 }, + }; + + + + + + + + + + + + + + +/* + Entry point into Q3SH. + Intercept console command to interpret as scripting constructs. + + Returns: + -1 - if nothing to intercept (i.e. run regular command check). + 0 - if intercepted with unknown construct (== unknown or bad command). + 1 - if intercepted with known construct (== known command). + + + The default declaration for a function is no-parameter with return type int. + Prototype for this function does not appear anywhere else, nor need to, as the default declaration holds true. + Horrid abuse of C-compiler customs. +*/ + +int +QSH_trap () +{ + int i; + int h; + int retval; + char cmd[256]; + +//debug("qsh_trap: start\n"); + if (qsh.magic != MAGIC_QSH) QSH_init(); + retval = -1; + QSH_argv(cmd, 0, sizeof(cmd)); +//debug("qsh_trap: cmd = [%s]\n", cmd); + h = QSH_hash(cmd); +//debug("qsh_trap: check hash = %08X\n", h); + for(i = 0; qshcmds[i].name; i++) + { +//debug("qsh_trap: check on [%s]\n", qshcmds[i].name); + if ((qshcmds[i].hash == h) && (0 == Q_stricmp(qshcmds[i].name, cmd))) + { +//debug("qsh_trap: match on [%s]\n", qshcmds[i].name); + retval = qshcmds[i].func(qsh.qout, qsh.qerr, ""); + Com_Printf("%s", qsh.qerr); + Com_Printf("%s", qsh.qout); + qsh.qerr[0] = 0; + qsh.qout[0] = 0; + break; + } + } +//debug("qsh_trap: done\n"); + return retval; +} + + + + + + +int +QSH_init () +{ + int i; + + memset(&qsh, 0, sizeof(qsh)); + qsh.magic = MAGIC_QSH; + for(i = 0; qshcmds[i].name; i++) + { + qshcmds[i].hash = QSH_hash(qshcmds[i].name); + } + qsh.numintern = i; + + return 1; +} + +void +QSH_destroy() +{ + memset(&qsh, 0, sizeof(qsh)); +} + + + +