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:
Brian Koropoff 2003-02-16 19:46:34 +00:00
parent af520a373a
commit 760210dc7b
14 changed files with 151 additions and 69 deletions

View file

@ -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 {

View file

@ -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

View file

@ -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);

View file

@ -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},

View file

@ -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);

View file

@ -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;
}

View file

@ -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)

View file

@ -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 == '\"')

View file

@ -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;
}
}

View file

@ -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)

View file

@ -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);

View file

@ -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)

View file

@ -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 ();

View file

@ -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;