Added thread support to GIB and cleaned up escape characters yet again.

With any luck it should actually work this time.  Added the getimpulse
command so that GIB scripts can check if an impulse command is pending
before sending their own.  Fixed all the memory leaks I could find.
QuakeC and GIB seem to be clean except for maybe one or two sneaky leaks
I can't track down.
This commit is contained in:
Brian Koropoff 2002-05-11 00:36:12 +00:00
parent 73e6cf062c
commit 3fffa26fb4
6 changed files with 226 additions and 109 deletions

View file

@ -89,6 +89,12 @@ typedef struct cmd_buffer_s {
struct cmd_buffer_s *prev, *next; // Neighboring buffers in stack
} cmd_buffer_t;
typedef struct cmd_thread_s {
struct cmd_buffer_s *cbuf;
long int id;
struct cmd_thread_s *prev, *next;
} cmd_thread_t;
//===========================================================================
void escape (dstring_t * dstr, const char *clist);

View file

@ -122,6 +122,7 @@ menu_free (void *_m, void *unused)
free ((char*)p->name);
free (p);
}
free (m);
}
static void

View file

@ -402,12 +402,16 @@ static void
bi_strh_clear (progs_t *pr, void *data)
{
strh_resources_t *res = (strh_resources_t *)data;
int i,d;
int i,d,n;
for (i = 0; i < res->cnt_hashes; i++) {
if (res->hashes[i]) {
for(d = 0; d < res->hashes[i]->cnt_elements; d++) {
free(res->hashes[i]->elements[d]);
free(res->hashes[i]->elements[d]->key); // Free the key
for (n = 0; n < MAX_SH_VALUES; n++) // Free all values
if (res->hashes[i]->elements[d]->values[n])
free(res->hashes[i]->elements[d]->values[n]);
free(res->hashes[i]->elements[d]); // Free the element itself
}
free(res->hashes[i]->elements);
free(res->hashes[i]);

View file

@ -63,11 +63,6 @@ typedef struct cmdalias_s {
cmdalias_t *cmd_alias;
cmd_source_t cmd_source;
/* FIXME: All these separate buffers are sort of hacky
The command buffer interface should be generalized and
each part of QF (console, stufftext, config files and scripts)
that needs one should allocate and maintain its own.
*/
cmd_buffer_t *cmd_consolebuffer; // Console buffer
cmd_buffer_t *cmd_legacybuffer; // Server stuffcmd buffer with
// absolute backwards-compatibility
@ -77,6 +72,10 @@ cmd_buffer_t *cmd_activebuffer; // Buffer currently being executed
cmd_buffer_t *cmd_recycled; // Recycled buffers
cmd_thread_t *cmd_threads; // Detached buffers running by themselves
long int cmd_threadid; // The id of the last thread + 1
dstring_t *cmd_backtrace;
qboolean cmd_error;
@ -89,7 +88,7 @@ hashtab_t *cmd_hash;
//=============================================================================
/* Local variable stuff */
/* Structure management */
cmd_localvar_t *
Cmd_NewLocal (const char *key, const char *value)
@ -221,6 +220,45 @@ Cmd_FreeStack (cmd_buffer_t *stack) {
}
cmd_thread_t *
Cmd_NewThread (long int id) {
cmd_thread_t *new;
new = calloc (1, sizeof(cmd_thread_t));
SYS_CHECKMEM (new);
new->id = id;
new->cbuf = Cmd_NewBuffer (true);
return new;
}
void
Cmd_FreeThread (cmd_thread_t *thread) {
Cmd_FreeBuffer (thread->cbuf);
free (thread);
return;
}
void
Cmd_AddThread (cmd_thread_t **list, cmd_thread_t *thread) {
thread->next = *list;
thread->prev = 0;
if (*list)
(*list)->prev = thread;
*list = thread;
}
void
Cmd_RemoveThread (cmd_thread_t **list, cmd_thread_t *thread) {
if (thread == *list)
*list = thread->next;
if (thread->next)
thread->next->prev = thread->prev;
if (thread->prev)
thread->prev->next = thread->next;
Cmd_FreeThread (thread);
}
/*void
Cmd_FreeBuffer (cmd_buffer_t *del)
{
@ -345,6 +383,8 @@ Cbuf_Init (void)
cmd_activebuffer = cmd_consolebuffer;
cmd_threads = 0;
cmd_threadid = 0;
cmd_recycled = 0;
cmd_backtrace = dstring_newstr ();
@ -480,7 +520,6 @@ Cbuf_ExecuteBuffer (cmd_buffer_t *buffer)
Cbuf_ExtractLine (buffer->buffer, buf, buffer->legacy);
if (!buf->str[0])
continue;
Sys_DPrintf("Cbuf_ExecuteBuffer: Executing line %s\n", buf->str);
Cmd_TokenizeString (buf->str, cmd_activebuffer->legacy);
if (cmd_error)
break;
@ -547,6 +586,16 @@ Cbuf_ExecuteStack (cmd_buffer_t *buffer)
void
Cbuf_Execute (void)
{
cmd_thread_t *t, *temp;
for (t = cmd_threads; t; t = temp) {
temp = t->next;
if (!t->cbuf->next && !t->cbuf->buffer->str[0]) {
Cmd_RemoveThread (&cmd_threads, t);
continue;
}
Cbuf_ExecuteStack (t->cbuf);
}
Cbuf_ExecuteStack (cmd_keybindbuffer);
Cbuf_ExecuteStack (cmd_consolebuffer);
Cbuf_ExecuteStack (cmd_legacybuffer);
@ -1093,9 +1142,7 @@ Cmd_ProcessMath (dstring_t * dstr)
statement = dstring_newstr ();
for (i = 0; i < strlen (dstr->str); i++) {
if (dstr->str[i] == '#' && dstr->str[i + 1] == '{') {
if (!escaped (dstr->str, i)) {
i -= unescape (dstr, i);
if (dstr->str[i] == '#' && dstr->str[i + 1] == '{' && !escaped (dstr->str, i)) {
n = Cmd_EndBrace (dstr->str+i+1)+1;
if (n < 0) {
Cmd_Error ("Unmatched brace in math expression.\n");
@ -1116,8 +1163,6 @@ Cmd_ProcessMath (dstring_t * dstr)
Cmd_Error (va("Math error: invalid expression %s\n", statement->str));
break; // Math evaluation error
}
} else
i -= unescape (dstr, i);
}
}
dstring_delete (statement);
@ -1183,9 +1228,7 @@ Cmd_ProcessVariablesRecursive (dstring_t * dstr, int start)
if (dstr->str[start+1] == '{')
braces = 1;
for (i = start + 1 + braces;; i++) {
if (dstr->str[i] == '$' && (braces || dstr->str[i-1] == '$')) {
if (!escaped (dstr->str, i)) {
i -= unescape (dstr, i);
if (dstr->str[i] == '$' && (braces || dstr->str[i-1] == '$') && !escaped (dstr->str, i)) {
n = Cmd_ProcessVariablesRecursive (dstr, i);
if (n < 0) {
break;
@ -1193,8 +1236,6 @@ Cmd_ProcessVariablesRecursive (dstring_t * dstr, int start)
i += n - 1;
continue;
}
} else
i -= unescape (dstr, i);
} else if (!dstr->str[i] && braces) { // No closing brace
Cmd_Error ("Unmatched brace in variable substitution expression.\n");
n = -1;
@ -1214,6 +1255,8 @@ Cmd_ProcessVariablesRecursive (dstring_t * dstr, int start)
// Then cvars
dstring_appendstr (copy, cvar->string);
}
n = 0;
dstring_clearstr (varname); // Reuse variable
if (dstr->str[start] == '[') {
int val1, val2, res;
res = Cmd_ProcessIndex (dstr, start, &val1, &val2);
@ -1221,16 +1264,16 @@ Cmd_ProcessVariablesRecursive (dstring_t * dstr, int start)
n = -1;
else if (val1 >= strlen(copy->str) || val1 < 0)
n = 0;
else if (val2 < strlen(copy->str)) {
dstring_insert (dstr, copy->str+val1, val2-val1+1, start);
n = val2 - val1 + 1;
} else {
dstring_insert (dstr, copy->str+val1, strlen(copy->str)-val1, start);
n = strlen(copy->str)-val1;
}
} else {
dstring_insertstr (dstr, copy->str, start);
n = strlen(copy->str);
else if (val2 < strlen(copy->str))
dstring_insert (varname, copy->str+val1, val2-val1+1, 0);
else
dstring_insert (varname, copy->str+val1, strlen(copy->str)-val1, 0);
} else
dstring_appendstr (varname, copy->str);
if (n >= 0) {
escape (varname, "\\");
dstring_insertstr (dstr, varname->str, start);
n = strlen(varname->str);
}
dstring_delete (copy);
dstring_delete (varname);
@ -1258,6 +1301,7 @@ Cmd_ProcessEmbeddedSingle (dstring_t * dstr, int start)
return -1;
}
if (cmd_activebuffer->returned == cmd_returned) {
escape (cmd_activebuffer->retval, "\\");
dstring_snip(dstr, start, n+1);
dstring_insertstr (dstr, cmd_activebuffer->retval->str, start);
n = strlen(cmd_activebuffer->retval->str);
@ -1283,9 +1327,7 @@ Cmd_ProcessEmbedded (cmd_token_t *tok, dstring_t * dstr)
int i, n;
for (i = tok->pos; i < strlen(dstr->str); i++) {
if (dstr->str[i] == '~' && dstr->str[i+1] == '{') {
if (!escaped (dstr->str, i)) {
i -= unescape (dstr, i);
if (dstr->str[i] == '~' && dstr->str[i+1] == '{' && !escaped (dstr->str, i)) {
n = Cmd_ProcessEmbeddedSingle (dstr, i);
if (n == -2) {
tok->pos = i;
@ -1295,8 +1337,6 @@ Cmd_ProcessEmbedded (cmd_token_t *tok, dstring_t * dstr)
return n;
else
i += n-1;
} else
i -= unescape (dstr, i);
}
}
return 0;
@ -1308,16 +1348,12 @@ Cmd_ProcessVariables (dstring_t * dstr)
int i, n;
for (i = 0; i < strlen (dstr->str); i++) {
if (dstr->str[i] == '$') {
if (!escaped (dstr->str, i)) {
i -= unescape (dstr, i);
if (dstr->str[i] == '$' && !escaped (dstr->str, i)) {
n = Cmd_ProcessVariablesRecursive (dstr, i);
if (n < 0)
return n;
else
i += n - 1;
} else
i -= unescape (dstr, i);
}
}
return 0;
@ -1335,27 +1371,24 @@ Cmd_ProcessVariables (dstring_t * dstr)
tags, etc. can be escaped
*/
void
int
Cmd_ProcessEscapes (dstring_t * dstr, const char *noprocess)
{
int i;
if (strlen(dstr->str) == 1)
return;
for (i = 1; i <= strlen (dstr->str); i++) {
if (!(dstr->str[i] && strchr (noprocess, dstr->str[i])) && dstr->str[i-1] == '\\' && dstr->str[i] != '\\') {
if (dstr->str[i] == 'n' && escaped (dstr->str, i))
dstr->str[i] = '\n';
i -= unescape (dstr, i);
}
return 0;
for (i = 0; i < strlen (dstr->str); i++)
if (dstr->str[i] == '\\') {
dstring_snip (dstr, i, 1);
}
return 0;
}
int
Cmd_ProcessToken (cmd_token_t *token)
{
int res;
Cmd_ProcessEscapes (token->processed, "$#~");
res = Cmd_ProcessEmbedded (token, token->processed);
if (res < 0)
return res;
@ -1366,6 +1399,9 @@ Cmd_ProcessToken (cmd_token_t *token)
if (res < 0)
return res;
Cmd_ProcessTags (token->processed);
res = Cmd_ProcessEscapes (token->processed, "$#~");
if (res < 0)
return res;
token->state = cmd_done;
return 0;
}
@ -2004,6 +2040,10 @@ Cmd_For_f (void) {
Cmd_ExecuteSubroutine (sub);
} else
Cmd_Error("Malformed for statement.\n");
dstring_delete (arg1);
dstring_delete (init);
dstring_delete (cond);
dstring_delete (inc);
return;
}
@ -2096,6 +2136,53 @@ Cmd_Strlen_f (void)
Cmd_Return (va("%ld", (long) strlen (Cmd_Argv(1))));
}
void
Cmd_Detach_f (void)
{
cmd_thread_t *thread;
if (Cmd_Argc () != 2) {
Cmd_Error ("detach: invalid number of arguments.\n");
return;
}
thread = Cmd_NewThread (cmd_threadid++);
Cmd_AddThread (&cmd_threads, thread);
Cbuf_AddTextTo (thread->cbuf, Cmd_Argv(1));
Cbuf_ExecuteStack (thread->cbuf); // Execute it now
cmd_error = false; // Don't let errors cross into this stack
Cmd_Return (va("%li", thread->id));
}
void
Cmd_Killthread_f (void)
{
long int id;
cmd_thread_t *t;
if (Cmd_Argc() != 2)
Cmd_Error ("killthread: invalid number of arguments.\n");
id = atol (Cmd_Argv(1));
for (t = cmd_threads; t; t = t->next)
if (id == t->id) {
if (t->cbuf->next)
Cmd_FreeStack (t->cbuf->next);
t->cbuf->next = 0;
dstring_clearstr (t->cbuf->buffer);
return;
}
Cmd_Error ("kill: invalid thread id\n");
}
void
Cmd_Threadstats_f (void)
{
cmd_thread_t *t;
Sys_Printf ("Currently running threads:\n");
for (t = cmd_threads; t; t = t->next)
Sys_Printf("%li\n", t->id);
}
void
Cmd_Hash_Stats_f (void)
{
@ -2179,6 +2266,9 @@ Cmd_Init (void)
Cmd_AddCommand ("randint", Cmd_Randint_f, "Returns a random integer between $1 and $2");
Cmd_AddCommand ("streq", Cmd_Streq_f, "Returns 1 if $1 and $2 are the same string, 0 otherwise");
Cmd_AddCommand ("strlen", Cmd_Strlen_f, "Returns the length of $1");
Cmd_AddCommand ("detach", Cmd_Detach_f, "Starts a thread with an initial program of $1");
Cmd_AddCommand ("killthread", Cmd_Killthread_f, "Kills thread with id $1");
Cmd_AddCommand ("threadstats", Cmd_Threadstats_f, "Shows statistics about threads");
//Cmd_AddCommand ("cmd_hash_stats", Cmd_Hash_Stats_f, "Display statistics "
// "alias and command hash tables");

View file

@ -45,6 +45,7 @@ static const char rcsid[] =
#include "QF/keys.h"
#include "QF/msg.h"
#include "QF/teamplay.h"
#include "QF/va.h"
#include "cl_cam.h"
#include "cl_demo.h"
@ -365,6 +366,12 @@ IN_Impulse (void)
Team_BestWeaponImpulse (); // HACK HACK HACK
}
void
IN_Getimpulse_f (void)
{
Cmd_Return(va("%i", in_impulse));
}
/*
CL_KeyState
@ -795,6 +802,8 @@ CL_Input_Init (void)
"jumping");
Cmd_AddCommand ("impulse", IN_Impulse, "Call a game function or QuakeC "
"function.");
Cmd_AddCommand ("getimpulse", IN_Getimpulse_f, "Returns the impulse that "
"will be sent to the server this frame");
Cmd_AddCommand ("+klook", IN_KLookDown, "When active, +forward and +back "
"perform +lookup and +lookdown");
Cmd_AddCommand ("-klook", IN_KLookUp, "When active, +forward and +back "

View file

@ -453,6 +453,7 @@ void
CL_Disconnect (void)
{
byte final[10];
int i;
connect_time = -1;
@ -494,6 +495,12 @@ CL_Disconnect (void)
Team_ResetTimers ();
// remove player info strings
for (i = 0; i < MAX_CLIENTS; i++)
if (cl.players[i].userinfo) {
Info_Destroy (cl.players[i].userinfo);
cl.players[i].userinfo = 0;
}
}
void