mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-18 06:51:47 +00:00
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:
parent
73e6cf062c
commit
3fffa26fb4
6 changed files with 226 additions and 109 deletions
|
@ -89,6 +89,12 @@ typedef struct cmd_buffer_s {
|
||||||
struct cmd_buffer_s *prev, *next; // Neighboring buffers in stack
|
struct cmd_buffer_s *prev, *next; // Neighboring buffers in stack
|
||||||
} cmd_buffer_t;
|
} 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);
|
void escape (dstring_t * dstr, const char *clist);
|
||||||
|
|
|
@ -122,6 +122,7 @@ menu_free (void *_m, void *unused)
|
||||||
free ((char*)p->name);
|
free ((char*)p->name);
|
||||||
free (p);
|
free (p);
|
||||||
}
|
}
|
||||||
|
free (m);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -402,12 +402,16 @@ static void
|
||||||
bi_strh_clear (progs_t *pr, void *data)
|
bi_strh_clear (progs_t *pr, void *data)
|
||||||
{
|
{
|
||||||
strh_resources_t *res = (strh_resources_t *)data;
|
strh_resources_t *res = (strh_resources_t *)data;
|
||||||
int i,d;
|
int i,d,n;
|
||||||
|
|
||||||
for (i = 0; i < res->cnt_hashes; i++) {
|
for (i = 0; i < res->cnt_hashes; i++) {
|
||||||
if (res->hashes[i]) {
|
if (res->hashes[i]) {
|
||||||
for(d = 0; d < res->hashes[i]->cnt_elements; d++) {
|
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]->elements);
|
||||||
free(res->hashes[i]);
|
free(res->hashes[i]);
|
||||||
|
|
272
libs/util/cmd.c
272
libs/util/cmd.c
|
@ -63,19 +63,18 @@ typedef struct cmdalias_s {
|
||||||
cmdalias_t *cmd_alias;
|
cmdalias_t *cmd_alias;
|
||||||
cmd_source_t cmd_source;
|
cmd_source_t cmd_source;
|
||||||
|
|
||||||
/* FIXME: All these separate buffers are sort of hacky
|
cmd_buffer_t *cmd_consolebuffer; // Console buffer
|
||||||
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
|
cmd_buffer_t *cmd_legacybuffer; // Server stuffcmd buffer with
|
||||||
// absolute backwards-compatibility
|
// absolute backwards-compatibility
|
||||||
cmd_buffer_t *cmd_privatebuffer; // Buffer for internal command execution
|
cmd_buffer_t *cmd_privatebuffer; // Buffer for internal command execution
|
||||||
cmd_buffer_t *cmd_keybindbuffer; // Buffer for commands from bound keys
|
cmd_buffer_t *cmd_keybindbuffer; // Buffer for commands from bound keys
|
||||||
cmd_buffer_t *cmd_activebuffer; // Buffer currently being executed
|
cmd_buffer_t *cmd_activebuffer; // Buffer currently being executed
|
||||||
|
|
||||||
cmd_buffer_t *cmd_recycled; // Recycled buffers
|
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;
|
dstring_t *cmd_backtrace;
|
||||||
|
|
||||||
|
@ -89,7 +88,7 @@ hashtab_t *cmd_hash;
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
/* Local variable stuff */
|
/* Structure management */
|
||||||
|
|
||||||
cmd_localvar_t *
|
cmd_localvar_t *
|
||||||
Cmd_NewLocal (const char *key, const char *value)
|
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
|
/*void
|
||||||
Cmd_FreeBuffer (cmd_buffer_t *del)
|
Cmd_FreeBuffer (cmd_buffer_t *del)
|
||||||
{
|
{
|
||||||
|
@ -345,6 +383,8 @@ Cbuf_Init (void)
|
||||||
|
|
||||||
cmd_activebuffer = cmd_consolebuffer;
|
cmd_activebuffer = cmd_consolebuffer;
|
||||||
|
|
||||||
|
cmd_threads = 0;
|
||||||
|
cmd_threadid = 0;
|
||||||
cmd_recycled = 0;
|
cmd_recycled = 0;
|
||||||
|
|
||||||
cmd_backtrace = dstring_newstr ();
|
cmd_backtrace = dstring_newstr ();
|
||||||
|
@ -480,7 +520,6 @@ Cbuf_ExecuteBuffer (cmd_buffer_t *buffer)
|
||||||
Cbuf_ExtractLine (buffer->buffer, buf, buffer->legacy);
|
Cbuf_ExtractLine (buffer->buffer, buf, buffer->legacy);
|
||||||
if (!buf->str[0])
|
if (!buf->str[0])
|
||||||
continue;
|
continue;
|
||||||
Sys_DPrintf("Cbuf_ExecuteBuffer: Executing line %s\n", buf->str);
|
|
||||||
Cmd_TokenizeString (buf->str, cmd_activebuffer->legacy);
|
Cmd_TokenizeString (buf->str, cmd_activebuffer->legacy);
|
||||||
if (cmd_error)
|
if (cmd_error)
|
||||||
break;
|
break;
|
||||||
|
@ -547,6 +586,16 @@ Cbuf_ExecuteStack (cmd_buffer_t *buffer)
|
||||||
void
|
void
|
||||||
Cbuf_Execute (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_keybindbuffer);
|
||||||
Cbuf_ExecuteStack (cmd_consolebuffer);
|
Cbuf_ExecuteStack (cmd_consolebuffer);
|
||||||
Cbuf_ExecuteStack (cmd_legacybuffer);
|
Cbuf_ExecuteStack (cmd_legacybuffer);
|
||||||
|
@ -1093,31 +1142,27 @@ Cmd_ProcessMath (dstring_t * dstr)
|
||||||
statement = dstring_newstr ();
|
statement = dstring_newstr ();
|
||||||
|
|
||||||
for (i = 0; i < strlen (dstr->str); i++) {
|
for (i = 0; i < strlen (dstr->str); i++) {
|
||||||
if (dstr->str[i] == '#' && dstr->str[i + 1] == '{') {
|
if (dstr->str[i] == '#' && dstr->str[i + 1] == '{' && !escaped (dstr->str, i)) {
|
||||||
if (!escaped (dstr->str, i)) {
|
n = Cmd_EndBrace (dstr->str+i+1)+1;
|
||||||
i -= unescape (dstr, i);
|
if (n < 0) {
|
||||||
n = Cmd_EndBrace (dstr->str+i+1)+1;
|
Cmd_Error ("Unmatched brace in math expression.\n");
|
||||||
if (n < 0) {
|
ret = -1;
|
||||||
Cmd_Error ("Unmatched brace in math expression.\n");
|
break;
|
||||||
ret = -1;
|
}
|
||||||
break;
|
/* Copy text between parentheses into a buffer */
|
||||||
}
|
dstring_clearstr (statement);
|
||||||
/* Copy text between parentheses into a buffer */
|
dstring_insert (statement, dstr->str + i + 2, n - 2, 0);
|
||||||
dstring_clearstr (statement);
|
value = EXP_Evaluate (statement->str);
|
||||||
dstring_insert (statement, dstr->str + i + 2, n - 2, 0);
|
if (EXP_ERROR == EXP_E_NORMAL) {
|
||||||
value = EXP_Evaluate (statement->str);
|
temp = va ("%.10g", value);
|
||||||
if (EXP_ERROR == EXP_E_NORMAL) {
|
dstring_snip (dstr, i, n + 1); // Nuke the statement
|
||||||
temp = va ("%.10g", value);
|
dstring_insertstr (dstr, temp, i); // Stick in the value
|
||||||
dstring_snip (dstr, i, n + 1); // Nuke the statement
|
i += strlen (temp) - 1;
|
||||||
dstring_insertstr (dstr, temp, i); // Stick in the value
|
} else {
|
||||||
i += strlen (temp) - 1;
|
ret = -2;
|
||||||
} else {
|
Cmd_Error (va("Math error: invalid expression %s\n", statement->str));
|
||||||
ret = -2;
|
break; // Math evaluation error
|
||||||
Cmd_Error (va("Math error: invalid expression %s\n", statement->str));
|
}
|
||||||
break; // Math evaluation error
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
i -= unescape (dstr, i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dstring_delete (statement);
|
dstring_delete (statement);
|
||||||
|
@ -1183,18 +1228,14 @@ Cmd_ProcessVariablesRecursive (dstring_t * dstr, int start)
|
||||||
if (dstr->str[start+1] == '{')
|
if (dstr->str[start+1] == '{')
|
||||||
braces = 1;
|
braces = 1;
|
||||||
for (i = start + 1 + braces;; i++) {
|
for (i = start + 1 + braces;; i++) {
|
||||||
if (dstr->str[i] == '$' && (braces || dstr->str[i-1] == '$')) {
|
if (dstr->str[i] == '$' && (braces || dstr->str[i-1] == '$') && !escaped (dstr->str, i)) {
|
||||||
if (!escaped (dstr->str, i)) {
|
n = Cmd_ProcessVariablesRecursive (dstr, i);
|
||||||
i -= unescape (dstr, i);
|
if (n < 0) {
|
||||||
n = Cmd_ProcessVariablesRecursive (dstr, i);
|
break;
|
||||||
if (n < 0) {
|
} else {
|
||||||
break;
|
i += n - 1;
|
||||||
} else {
|
continue;
|
||||||
i += n - 1;
|
}
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
i -= unescape (dstr, i);
|
|
||||||
} else if (!dstr->str[i] && braces) { // No closing brace
|
} else if (!dstr->str[i] && braces) { // No closing brace
|
||||||
Cmd_Error ("Unmatched brace in variable substitution expression.\n");
|
Cmd_Error ("Unmatched brace in variable substitution expression.\n");
|
||||||
n = -1;
|
n = -1;
|
||||||
|
@ -1214,6 +1255,8 @@ Cmd_ProcessVariablesRecursive (dstring_t * dstr, int start)
|
||||||
// Then cvars
|
// Then cvars
|
||||||
dstring_appendstr (copy, cvar->string);
|
dstring_appendstr (copy, cvar->string);
|
||||||
}
|
}
|
||||||
|
n = 0;
|
||||||
|
dstring_clearstr (varname); // Reuse variable
|
||||||
if (dstr->str[start] == '[') {
|
if (dstr->str[start] == '[') {
|
||||||
int val1, val2, res;
|
int val1, val2, res;
|
||||||
res = Cmd_ProcessIndex (dstr, start, &val1, &val2);
|
res = Cmd_ProcessIndex (dstr, start, &val1, &val2);
|
||||||
|
@ -1221,16 +1264,16 @@ Cmd_ProcessVariablesRecursive (dstring_t * dstr, int start)
|
||||||
n = -1;
|
n = -1;
|
||||||
else if (val1 >= strlen(copy->str) || val1 < 0)
|
else if (val1 >= strlen(copy->str) || val1 < 0)
|
||||||
n = 0;
|
n = 0;
|
||||||
else if (val2 < strlen(copy->str)) {
|
else if (val2 < strlen(copy->str))
|
||||||
dstring_insert (dstr, copy->str+val1, val2-val1+1, start);
|
dstring_insert (varname, copy->str+val1, val2-val1+1, 0);
|
||||||
n = val2 - val1 + 1;
|
else
|
||||||
} else {
|
dstring_insert (varname, copy->str+val1, strlen(copy->str)-val1, 0);
|
||||||
dstring_insert (dstr, copy->str+val1, strlen(copy->str)-val1, start);
|
} else
|
||||||
n = strlen(copy->str)-val1;
|
dstring_appendstr (varname, copy->str);
|
||||||
}
|
if (n >= 0) {
|
||||||
} else {
|
escape (varname, "\\");
|
||||||
dstring_insertstr (dstr, copy->str, start);
|
dstring_insertstr (dstr, varname->str, start);
|
||||||
n = strlen(copy->str);
|
n = strlen(varname->str);
|
||||||
}
|
}
|
||||||
dstring_delete (copy);
|
dstring_delete (copy);
|
||||||
dstring_delete (varname);
|
dstring_delete (varname);
|
||||||
|
@ -1258,6 +1301,7 @@ Cmd_ProcessEmbeddedSingle (dstring_t * dstr, int start)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (cmd_activebuffer->returned == cmd_returned) {
|
if (cmd_activebuffer->returned == cmd_returned) {
|
||||||
|
escape (cmd_activebuffer->retval, "\\");
|
||||||
dstring_snip(dstr, start, n+1);
|
dstring_snip(dstr, start, n+1);
|
||||||
dstring_insertstr (dstr, cmd_activebuffer->retval->str, start);
|
dstring_insertstr (dstr, cmd_activebuffer->retval->str, start);
|
||||||
n = strlen(cmd_activebuffer->retval->str);
|
n = strlen(cmd_activebuffer->retval->str);
|
||||||
|
@ -1283,20 +1327,16 @@ Cmd_ProcessEmbedded (cmd_token_t *tok, dstring_t * dstr)
|
||||||
int i, n;
|
int i, n;
|
||||||
|
|
||||||
for (i = tok->pos; i < strlen(dstr->str); i++) {
|
for (i = tok->pos; i < strlen(dstr->str); i++) {
|
||||||
if (dstr->str[i] == '~' && dstr->str[i+1] == '{') {
|
if (dstr->str[i] == '~' && dstr->str[i+1] == '{' && !escaped (dstr->str, i)) {
|
||||||
if (!escaped (dstr->str, i)) {
|
n = Cmd_ProcessEmbeddedSingle (dstr, i);
|
||||||
i -= unescape (dstr, i);
|
if (n == -2) {
|
||||||
n = Cmd_ProcessEmbeddedSingle (dstr, i);
|
tok->pos = i;
|
||||||
if (n == -2) {
|
return n;
|
||||||
tok->pos = i;
|
}
|
||||||
return n;
|
if (n < 0)
|
||||||
}
|
return n;
|
||||||
if (n < 0)
|
else
|
||||||
return n;
|
i += n-1;
|
||||||
else
|
|
||||||
i += n-1;
|
|
||||||
} else
|
|
||||||
i -= unescape (dstr, i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1308,16 +1348,12 @@ Cmd_ProcessVariables (dstring_t * dstr)
|
||||||
int i, n;
|
int i, n;
|
||||||
|
|
||||||
for (i = 0; i < strlen (dstr->str); i++) {
|
for (i = 0; i < strlen (dstr->str); i++) {
|
||||||
if (dstr->str[i] == '$') {
|
if (dstr->str[i] == '$' && !escaped (dstr->str, i)) {
|
||||||
if (!escaped (dstr->str, i)) {
|
n = Cmd_ProcessVariablesRecursive (dstr, i);
|
||||||
i -= unescape (dstr, i);
|
if (n < 0)
|
||||||
n = Cmd_ProcessVariablesRecursive (dstr, i);
|
return n;
|
||||||
if (n < 0)
|
else
|
||||||
return n;
|
i += n - 1;
|
||||||
else
|
|
||||||
i += n - 1;
|
|
||||||
} else
|
|
||||||
i -= unescape (dstr, i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1335,27 +1371,24 @@ Cmd_ProcessVariables (dstring_t * dstr)
|
||||||
tags, etc. can be escaped
|
tags, etc. can be escaped
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
int
|
||||||
Cmd_ProcessEscapes (dstring_t * dstr, const char *noprocess)
|
Cmd_ProcessEscapes (dstring_t * dstr, const char *noprocess)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (strlen(dstr->str) == 1)
|
if (strlen(dstr->str) == 1)
|
||||||
return;
|
return 0;
|
||||||
for (i = 1; i <= strlen (dstr->str); i++) {
|
for (i = 0; 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] == '\\') {
|
||||||
if (dstr->str[i] == 'n' && escaped (dstr->str, i))
|
dstring_snip (dstr, i, 1);
|
||||||
dstr->str[i] = '\n';
|
|
||||||
i -= unescape (dstr, i);
|
|
||||||
}
|
}
|
||||||
}
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
Cmd_ProcessToken (cmd_token_t *token)
|
Cmd_ProcessToken (cmd_token_t *token)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
Cmd_ProcessEscapes (token->processed, "$#~");
|
|
||||||
res = Cmd_ProcessEmbedded (token, token->processed);
|
res = Cmd_ProcessEmbedded (token, token->processed);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
return res;
|
return res;
|
||||||
|
@ -1366,6 +1399,9 @@ Cmd_ProcessToken (cmd_token_t *token)
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
return res;
|
return res;
|
||||||
Cmd_ProcessTags (token->processed);
|
Cmd_ProcessTags (token->processed);
|
||||||
|
res = Cmd_ProcessEscapes (token->processed, "$#~");
|
||||||
|
if (res < 0)
|
||||||
|
return res;
|
||||||
token->state = cmd_done;
|
token->state = cmd_done;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2004,6 +2040,10 @@ Cmd_For_f (void) {
|
||||||
Cmd_ExecuteSubroutine (sub);
|
Cmd_ExecuteSubroutine (sub);
|
||||||
} else
|
} else
|
||||||
Cmd_Error("Malformed for statement.\n");
|
Cmd_Error("Malformed for statement.\n");
|
||||||
|
dstring_delete (arg1);
|
||||||
|
dstring_delete (init);
|
||||||
|
dstring_delete (cond);
|
||||||
|
dstring_delete (inc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2096,6 +2136,53 @@ Cmd_Strlen_f (void)
|
||||||
Cmd_Return (va("%ld", (long) strlen (Cmd_Argv(1))));
|
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
|
void
|
||||||
Cmd_Hash_Stats_f (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 ("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 ("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 ("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 "
|
//Cmd_AddCommand ("cmd_hash_stats", Cmd_Hash_Stats_f, "Display statistics "
|
||||||
// "alias and command hash tables");
|
// "alias and command hash tables");
|
||||||
|
|
|
@ -45,6 +45,7 @@ static const char rcsid[] =
|
||||||
#include "QF/keys.h"
|
#include "QF/keys.h"
|
||||||
#include "QF/msg.h"
|
#include "QF/msg.h"
|
||||||
#include "QF/teamplay.h"
|
#include "QF/teamplay.h"
|
||||||
|
#include "QF/va.h"
|
||||||
|
|
||||||
#include "cl_cam.h"
|
#include "cl_cam.h"
|
||||||
#include "cl_demo.h"
|
#include "cl_demo.h"
|
||||||
|
@ -365,6 +366,12 @@ IN_Impulse (void)
|
||||||
Team_BestWeaponImpulse (); // HACK HACK HACK
|
Team_BestWeaponImpulse (); // HACK HACK HACK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
IN_Getimpulse_f (void)
|
||||||
|
{
|
||||||
|
Cmd_Return(va("%i", in_impulse));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
CL_KeyState
|
CL_KeyState
|
||||||
|
|
||||||
|
@ -795,6 +802,8 @@ CL_Input_Init (void)
|
||||||
"jumping");
|
"jumping");
|
||||||
Cmd_AddCommand ("impulse", IN_Impulse, "Call a game function or QuakeC "
|
Cmd_AddCommand ("impulse", IN_Impulse, "Call a game function or QuakeC "
|
||||||
"function.");
|
"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 "
|
Cmd_AddCommand ("+klook", IN_KLookDown, "When active, +forward and +back "
|
||||||
"perform +lookup and +lookdown");
|
"perform +lookup and +lookdown");
|
||||||
Cmd_AddCommand ("-klook", IN_KLookUp, "When active, +forward and +back "
|
Cmd_AddCommand ("-klook", IN_KLookUp, "When active, +forward and +back "
|
||||||
|
|
|
@ -453,6 +453,7 @@ void
|
||||||
CL_Disconnect (void)
|
CL_Disconnect (void)
|
||||||
{
|
{
|
||||||
byte final[10];
|
byte final[10];
|
||||||
|
int i;
|
||||||
|
|
||||||
connect_time = -1;
|
connect_time = -1;
|
||||||
|
|
||||||
|
@ -494,6 +495,12 @@ CL_Disconnect (void)
|
||||||
|
|
||||||
Team_ResetTimers ();
|
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
|
void
|
||||||
|
|
Loading…
Reference in a new issue