mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 15:22:04 +00:00
GIB: Many bugfixes and cleanups. Added bitwise math operations, expansion
of leaf names in a stem variable via %var, the builtin functions 'count' and 'contains', and an initial interface between qw-server and GIB to allow querying of clients and their info strings. Also cleaned up the chat event interface a bit. Renamed a few builtins.
This commit is contained in:
parent
af520a373a
commit
760210dc7b
14 changed files with 151 additions and 69 deletions
|
@ -30,6 +30,7 @@
|
|||
*/
|
||||
|
||||
#include "QF/cbuf.h" // For cbuf_active
|
||||
#include "QF/gib_buffer.h" // For GIB_DATA()
|
||||
#include "QF/dstring.h" // For ->str
|
||||
|
||||
typedef struct gib_builtin_s {
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
// Flags for tokens
|
||||
#define TREE_CONCAT 1 // Concatenate to previous
|
||||
#define TREE_P_EMBED 2 // Embedded stuff needs to be processed
|
||||
#define TREE_ASPLIT 4 // Token is the name of an array that should be split
|
||||
#define TREE_SPLIT 4 // Token is the name of an array that should be split
|
||||
// Flags for lines
|
||||
#define TREE_COND 1 // Conditional jump (if or while command)
|
||||
#define TREE_NOT 2 // Invert condition
|
||||
|
|
|
@ -37,6 +37,10 @@ double OP_GreaterThan (double op1, double op2);
|
|||
double OP_LessThan (double op1, double op2);
|
||||
double OP_GreaterThanEqual (double op1, double op2);
|
||||
double OP_LessThanEqual (double op1, double op2);
|
||||
double OP_BitAnd (double op1, double op2);
|
||||
double OP_BitOr (double op1, double op2);
|
||||
double OP_BitXor (double op1, double op2);
|
||||
double OP_BitInv (double op1, double op2);
|
||||
|
||||
double Func_Sin (double *oplist, unsigned int numops);
|
||||
double Func_Cos (double *oplist, unsigned int numops);
|
||||
|
|
|
@ -34,7 +34,11 @@ exp_error_t EXP_ERROR;
|
|||
char *exp_error_msg = 0;
|
||||
|
||||
optable_t optable[] = {
|
||||
{"~", OP_BitInv, 1},
|
||||
{"!", OP_Not, 1},
|
||||
{"&", OP_BitAnd, 2},
|
||||
{"|", OP_BitOr, 2},
|
||||
{"^", OP_BitXor, 2},
|
||||
{"**", OP_Exp, 2},
|
||||
{"/", OP_Div, 2},
|
||||
{"-", OP_Negate, 1},
|
||||
|
|
|
@ -210,7 +210,7 @@ GIB_Local_f (void)
|
|||
GIB_Argc () - 3);
|
||||
} else for (i = 1; i < GIB_Argc(); i++)
|
||||
var = GIB_Var_Get_Complex (&GIB_DATA (cbuf_active)->locals, &zero,
|
||||
GIB_Argv (1), &index, true);
|
||||
GIB_Argv (i), &index, true);
|
||||
}
|
||||
|
||||
|
||||
|
@ -231,16 +231,15 @@ GIB_Global_f (void)
|
|||
GIB_Argc () - 3);
|
||||
} else for (i = 1; i < GIB_Argc(); i++)
|
||||
var = GIB_Var_Get_Complex (&GIB_DATA (cbuf_active)->globals, &zero,
|
||||
GIB_Argv (1), &index, true);
|
||||
GIB_Argv (i), &index, true);
|
||||
}
|
||||
|
||||
static void
|
||||
GIB_Global_Delete_f (void)
|
||||
GIB_Delete_f (void)
|
||||
{
|
||||
gib_var_t *var;
|
||||
unsigned int index, i;
|
||||
hashtab_t *source;
|
||||
static hashtab_t *zero = 0;
|
||||
char *c;
|
||||
|
||||
if (GIB_Argc () < 2)
|
||||
|
@ -248,7 +247,8 @@ GIB_Global_Delete_f (void)
|
|||
else for (i = 1; i < GIB_Argc(); i++) {
|
||||
if ((c = strrchr (GIB_Argv(i), '.'))) {
|
||||
*(c++) = 0;
|
||||
if (!(var = GIB_Var_Get_Complex (&GIB_DATA (cbuf_active)->globals, &zero,
|
||||
if (!(var = GIB_Var_Get_Complex (&GIB_DATA (cbuf_active)->locals,
|
||||
&GIB_DATA(cbuf_active)->globals,
|
||||
GIB_Argv (i), &index, false)))
|
||||
continue;
|
||||
source = var->array[index].leaves;
|
||||
|
@ -425,6 +425,27 @@ GIB_Equal_f (void)
|
|||
GIB_Return ("1");
|
||||
}
|
||||
|
||||
static void
|
||||
GIB_Count_f (void)
|
||||
{
|
||||
if (GIB_CanReturn())
|
||||
dsprintf (GIB_Return(0), "%u", GIB_Argc() - 1);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
GIB_Contains_f (void)
|
||||
{
|
||||
unsigned int i;
|
||||
if (GIB_Argc () < 2)
|
||||
GIB_USAGE ("needle [straw1 straw2 ...]");
|
||||
else if (GIB_CanReturn())
|
||||
for (i = 2; i < GIB_Argc(); i++)
|
||||
if (!strcmp(GIB_Argv(1), GIB_Argv(i)))
|
||||
GIB_Return("1");
|
||||
GIB_Return ("0");
|
||||
}
|
||||
|
||||
static void
|
||||
GIB_Slice_f (void)
|
||||
{
|
||||
|
@ -911,7 +932,7 @@ GIB_Builtin_Init (qboolean sandbox)
|
|||
GIB_Builtin_Add ("function::export", GIB_Function_Export_f);
|
||||
GIB_Builtin_Add ("local", GIB_Local_f);
|
||||
GIB_Builtin_Add ("global", GIB_Global_f);
|
||||
GIB_Builtin_Add ("global::delete", GIB_Global_Delete_f);
|
||||
GIB_Builtin_Add ("delete", GIB_Delete_f);
|
||||
GIB_Builtin_Add ("domain", GIB_Domain_f);
|
||||
GIB_Builtin_Add ("domain::clear", GIB_Domain_Clear_f);
|
||||
GIB_Builtin_Add ("return", GIB_Return_f);
|
||||
|
@ -920,6 +941,8 @@ GIB_Builtin_Init (qboolean sandbox)
|
|||
GIB_Builtin_Add ("continue", GIB_Continue_f);
|
||||
GIB_Builtin_Add ("length", GIB_Length_f);
|
||||
GIB_Builtin_Add ("equal", GIB_Equal_f);
|
||||
GIB_Builtin_Add ("count", GIB_Count_f);
|
||||
GIB_Builtin_Add ("contains", GIB_Contains_f);
|
||||
GIB_Builtin_Add ("slice", GIB_Slice_f);
|
||||
GIB_Builtin_Add ("slice::find", GIB_Slice_Find_f);
|
||||
GIB_Builtin_Add ("split", GIB_Split_f);
|
||||
|
@ -928,7 +951,7 @@ GIB_Builtin_Init (qboolean sandbox)
|
|||
GIB_Builtin_Add ("regex::extract", GIB_Regex_Extract_f);
|
||||
GIB_Builtin_Add ("thread::create", GIB_Thread_Create_f);
|
||||
GIB_Builtin_Add ("thread::kill", GIB_Thread_Kill_f);
|
||||
GIB_Builtin_Add ("thread::list", GIB_Thread_List_f);
|
||||
GIB_Builtin_Add ("thread::getList", GIB_Thread_List_f);
|
||||
GIB_Builtin_Add ("event::register", GIB_Event_Register_f);
|
||||
GIB_Builtin_Add ("file::read", GIB_File_Read_f);
|
||||
GIB_Builtin_Add ("file::write", GIB_File_Write_f);
|
||||
|
|
|
@ -76,7 +76,7 @@ GIB_Execute_Generate_Composite (struct cbuf_s *cbuf)
|
|||
}
|
||||
|
||||
static void
|
||||
GIB_Execute_Split_Array (cbuf_t * cbuf)
|
||||
GIB_Execute_Split_Var (cbuf_t * cbuf)
|
||||
{
|
||||
gib_var_t *var;
|
||||
unsigned int i;
|
||||
|
@ -85,6 +85,7 @@ GIB_Execute_Split_Array (cbuf_t * cbuf)
|
|||
void *m = cbuf->args->argm[cbuf->args->argc - 1];
|
||||
|
||||
i = strlen (str) - 1;
|
||||
if (str[-1] == '@') {
|
||||
if (str[i] == ']')
|
||||
for (; i; i--)
|
||||
if (str[i] == '[') {
|
||||
|
@ -118,6 +119,19 @@ GIB_Execute_Split_Array (cbuf_t * cbuf)
|
|||
Cbuf_ArgsAdd (cbuf->args, "");
|
||||
cbuf->args->argm[cbuf->args->argc - 1] = m;
|
||||
}
|
||||
} else {
|
||||
gib_var_t **vlist, **v;
|
||||
|
||||
cbuf->args->argc--;
|
||||
if (!(var = GIB_Var_Get_Complex (&GIB_DATA (cbuf)->locals,
|
||||
&GIB_DATA (cbuf)->globals, str, &i, false)))
|
||||
return;
|
||||
if (!var->array[i].leaves)
|
||||
return;
|
||||
vlist = (gib_var_t **) Hash_GetList (var->array[i].leaves);
|
||||
for (v = vlist; *v; v++)
|
||||
Cbuf_ArgsAdd (cbuf->args, (*v)->key);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -148,8 +162,8 @@ GIB_Execute_Prepare_Line (cbuf_t * cbuf, gib_tree_t * line)
|
|||
if (cur->delim == '('
|
||||
&& GIB_Process_Math (args->argv[args->argc - 1], pos))
|
||||
return -1;
|
||||
if (cur->flags & TREE_ASPLIT)
|
||||
GIB_Execute_Split_Array (cbuf);
|
||||
if (cur->flags & TREE_SPLIT)
|
||||
GIB_Execute_Split_Var (cbuf);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -158,8 +158,8 @@ GIB_Function_Prepare_Args (cbuf_t * cbuf, dstring_t ** args, unsigned int argc)
|
|||
|
||||
var =
|
||||
GIB_Var_Get_Complex (&GIB_DATA (cbuf)->locals, &zero, argss, &i, true);
|
||||
var->array = realloc (var->array, sizeof (dstring_t *) * argc);
|
||||
memset (var->array + 1, 0, (argc - 1) * sizeof (dstring_t *));
|
||||
var->array = realloc (var->array, sizeof (struct gib_varray_s) * argc);
|
||||
memset (var->array + 1, 0, (argc - 1) * sizeof (struct gib_varray_s));
|
||||
var->size = argc;
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (var->array[i].value)
|
||||
|
|
|
@ -321,7 +321,7 @@ GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int pofs,
|
|||
// Check for array splitting
|
||||
// Concatenating this onto something else is non-sensical
|
||||
if (cur->delim == ' ' && str[0] == '@' && !cat) {
|
||||
cur->flags |= TREE_ASPLIT;
|
||||
cur->flags |= TREE_SPLIT;
|
||||
}
|
||||
// We can handle escape characters now
|
||||
} else if (cur->delim == '\"')
|
||||
|
|
|
@ -95,20 +95,21 @@ GIB_Var_Get (hashtab_t * first, hashtab_t * second, const char *key)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Destroys key! */
|
||||
/* Alters key, but restores it */
|
||||
gib_var_t *
|
||||
GIB_Var_Get_Complex (hashtab_t ** first, hashtab_t ** second, char *key,
|
||||
unsigned int *ind, qboolean create)
|
||||
{
|
||||
static hashtab_t *zero = 0;
|
||||
unsigned int i, n, index, len, start;
|
||||
gib_var_t *var;
|
||||
unsigned int i, n, index = 0, len, start;
|
||||
gib_var_t *var = 0;
|
||||
|
||||
len = strlen(key);
|
||||
for (start = i = 0; i <= len; i++) {
|
||||
if (key[i] == '.' || key[i] == 0) {
|
||||
index = 0;
|
||||
key[i] = 0;
|
||||
n = 0;
|
||||
if (i && key[i - 1] == ']')
|
||||
for (n = i - 1; n; n--)
|
||||
if (key[n] == '[') {
|
||||
|
@ -128,9 +129,9 @@ GIB_Var_Get_Complex (hashtab_t ** first, hashtab_t ** second, char *key,
|
|||
if (index >= var->size) {
|
||||
if (create) {
|
||||
var->array =
|
||||
realloc (var->array, (index + 1) * sizeof (struct gib_varray_s *));
|
||||
realloc (var->array, (index + 1) * sizeof (struct gib_varray_s));
|
||||
memset (var->array + var->size, 0,
|
||||
(index + 1 - var->size) * sizeof (struct gib_varray_s *));
|
||||
(index + 1 - var->size) * sizeof (struct gib_varray_s));
|
||||
var->size = index + 1;
|
||||
} else
|
||||
return 0;
|
||||
|
@ -138,6 +139,10 @@ GIB_Var_Get_Complex (hashtab_t ** first, hashtab_t ** second, char *key,
|
|||
second = &zero;
|
||||
first = &var->array[index].leaves;
|
||||
start = i+1;
|
||||
if (n)
|
||||
key[n] = '[';
|
||||
if (i < len)
|
||||
key[i] = '.';
|
||||
}
|
||||
}
|
||||
if (!var->array[index].value)
|
||||
|
@ -146,19 +151,20 @@ GIB_Var_Get_Complex (hashtab_t ** first, hashtab_t ** second, char *key,
|
|||
return var;
|
||||
}
|
||||
|
||||
/* Mangles the hell out of key */
|
||||
gib_var_t *
|
||||
GIB_Var_Get_Very_Complex (hashtab_t ** first, hashtab_t ** second, dstring_t *key, unsigned int start,
|
||||
unsigned int *ind, qboolean create)
|
||||
{
|
||||
static hashtab_t *zero = 0;
|
||||
hashtab_t *one = *first, *two = *second;
|
||||
unsigned int i, index, index2, n;
|
||||
gib_var_t *var;
|
||||
unsigned int i, index = 0, index2 = 0, n, protect;
|
||||
gib_var_t *var = 0;
|
||||
cvar_t *cvar;
|
||||
char c, *str;
|
||||
qboolean done = false;
|
||||
|
||||
for (i = start; !done; i++) {
|
||||
for (i = start, protect = 0; !done; i++) {
|
||||
if (key->str[i] == '.' || key->str[i] == 0) {
|
||||
index = 0;
|
||||
if (!key->str[i])
|
||||
|
@ -193,7 +199,7 @@ GIB_Var_Get_Very_Complex (hashtab_t ** first, hashtab_t ** second, dstring_t *ke
|
|||
second = &zero;
|
||||
first = &var->array[index].leaves;
|
||||
start = i+1;
|
||||
} else if (key->str[i] == '$' || key->str[i] == '#') {
|
||||
} else if (i >= protect && (key->str[i] == '$' || key->str[i] == '#')) {
|
||||
n = i;
|
||||
if (GIB_Parse_Match_Var (key->str, &i))
|
||||
return 0;
|
||||
|
@ -204,13 +210,15 @@ GIB_Var_Get_Very_Complex (hashtab_t ** first, hashtab_t ** second, dstring_t *ke
|
|||
str = va("%u", var->size);
|
||||
else
|
||||
str = var->array[index2].value->str;
|
||||
dstring_replace (key, n, i-n, str, strlen (str));
|
||||
dstring_replace (key, n, i-n+(c == '}'), str, strlen (str));
|
||||
} else if (key->str[n] == '#')
|
||||
dstring_replace (key, n, i-n, "0", 1);
|
||||
dstring_replace (key, n, i-n+(c == '}'), "0", 1);
|
||||
else if ((cvar = Cvar_FindVar (key->str+n+1+(c == '}'))))
|
||||
dstring_replace (key, n, i-n, cvar->string, strlen (cvar->string));
|
||||
dstring_replace (key, n, i-n+(c == '}'), cvar->string, strlen (cvar->string));
|
||||
else
|
||||
dstring_snip (key, n, n-i);
|
||||
dstring_snip (key, n, n-i+(c == '}'));
|
||||
protect = i+1;
|
||||
i = n;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -113,6 +113,29 @@ OP_LessThanEqual (double op1, double op2)
|
|||
return op1 <= op2;
|
||||
}
|
||||
|
||||
double
|
||||
OP_BitAnd (double op1, double op2)
|
||||
{
|
||||
return (double) ((long int) op1 & (long int) op2);
|
||||
}
|
||||
|
||||
double
|
||||
OP_BitOr (double op1, double op2)
|
||||
{
|
||||
return (double) ((long int) op1 | (long int) op2);
|
||||
}
|
||||
|
||||
double
|
||||
OP_BitXor (double op1, double op2)
|
||||
{
|
||||
return (double) ((long int) op1 ^ (long int) op2);
|
||||
}
|
||||
|
||||
double
|
||||
OP_BitInv (double op1, double op2)
|
||||
{
|
||||
return (double) ~((long int) op1);
|
||||
}
|
||||
|
||||
double
|
||||
Func_Sin (double *oplist, unsigned int numops)
|
||||
|
|
|
@ -479,6 +479,7 @@ void SV_Physics_Client (struct edict_s *ent);
|
|||
void SV_SetupUserCommands (void);
|
||||
void SV_ExecuteUserCommand (const char *s);
|
||||
void SV_InitOperatorCommands (void);
|
||||
void SV_GIB_Init (void);
|
||||
|
||||
void SV_SendServerinfo (client_t *client);
|
||||
void SV_ExtractFromUserinfo (client_t *cl);
|
||||
|
|
|
@ -68,7 +68,7 @@ endif
|
|||
EXTRA_DIST=sv_sys_win.c sv_sys_unix.c
|
||||
|
||||
libqw_server_a_SOURCES= \
|
||||
crudefile.c sv_ccmds.c sv_demo.c sv_ents.c sv_init.c sv_main.c \
|
||||
crudefile.c sv_ccmds.c sv_demo.c sv_ents.c sv_gib.c sv_init.c sv_main.c \
|
||||
sv_move.c sv_nchan.c sv_phys.c sv_pr_cmds.c sv_progs.c sv_send.c \
|
||||
sv_user.c world.c $(syssv_SRC)
|
||||
|
||||
|
|
|
@ -2504,6 +2504,7 @@ SV_Init (void)
|
|||
svs.info = Info_ParseString ("", MAX_SERVERINFO_STRING);
|
||||
localinfo = Info_ParseString ("", 0); // unlimited
|
||||
SV_InitOperatorCommands ();
|
||||
SV_GIB_Init ();
|
||||
|
||||
QFS_Init ("qw");
|
||||
PI_Init ();
|
||||
|
|
|
@ -753,7 +753,7 @@ SV_Say (qboolean team)
|
|||
{
|
||||
char *i, *p;
|
||||
char text[2048], t1[32];
|
||||
const char *t2;
|
||||
const char *t2, *type;
|
||||
client_t *client;
|
||||
int tmp, j, cls = 0;
|
||||
|
||||
|
@ -765,12 +765,15 @@ SV_Say (qboolean team)
|
|||
t1[31] = 0;
|
||||
}
|
||||
|
||||
if (host_client->spectator && (!sv_spectalk->int_val || team))
|
||||
if (host_client->spectator && (!sv_spectalk->int_val || team)) {
|
||||
snprintf (text, sizeof (text), "[SPEC] %s: ", host_client->name);
|
||||
else if (team)
|
||||
type = "2";
|
||||
} else if (team) {
|
||||
snprintf (text, sizeof (text), "(%s): ", host_client->name);
|
||||
else {
|
||||
type = "1";
|
||||
} else {
|
||||
snprintf (text, sizeof (text), "%s: ", host_client->name);
|
||||
type = "0";
|
||||
}
|
||||
|
||||
if (fp_messages) {
|
||||
|
@ -823,14 +826,14 @@ SV_Say (qboolean team)
|
|||
*i = '#';
|
||||
}
|
||||
|
||||
if (sv_chat_e->func)
|
||||
GIB_Event_Callback (sv_chat_e, 2, va("%i", host_client->userid), p, type);
|
||||
|
||||
strncat (text, p, sizeof (text) - strlen (text));
|
||||
strncat (text, "\n", sizeof (text) - strlen (text));
|
||||
|
||||
SV_Printf ("%s", text);
|
||||
|
||||
if (sv_chat_e->func)
|
||||
GIB_Event_Callback (sv_chat_e, 1, text);
|
||||
|
||||
for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++) {
|
||||
if (client->state < cs_connected) // Clients connecting can hear.
|
||||
continue;
|
||||
|
|
Loading…
Reference in a new issue