mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-17 22:50:51 +00:00
Completely redid the way embedded functions are subroutines in general are
handled, meaning that execution can be paused at any time without a hitch. Warning: This is a major change to the architecture (or lack thereof) of GIB. Please test for bugs! Also, there are a few ugly bits of code that need to be cleaned up, but that work for now.
This commit is contained in:
parent
d4cc899d33
commit
cb79de3584
2 changed files with 206 additions and 121 deletions
|
@ -38,7 +38,14 @@ typedef struct cmd_localvar_s {
|
|||
|
||||
typedef struct cmd_token_s {
|
||||
struct dstring_s *original, *processed; // Token before and after processing
|
||||
unsigned int state; // Will be used later
|
||||
enum {
|
||||
cmd_original,
|
||||
cmd_process,
|
||||
cmd_done
|
||||
} state;
|
||||
unsigned int pos; // Last position in string (used by Cmd_ProcessEmbedded)
|
||||
unsigned int space; // Amount of white space before token
|
||||
char delim; // Character that delimeted token
|
||||
} cmd_token_t;
|
||||
|
||||
typedef struct cmd_buffer_s {
|
||||
|
@ -53,13 +60,26 @@ typedef struct cmd_buffer_s {
|
|||
unsigned int *args; // Array of positions of each token in composite line
|
||||
struct hashtab_s *locals; // Local variables
|
||||
|
||||
// Flags
|
||||
qboolean imperative; // Execution cannot be paused
|
||||
// Flags
|
||||
qboolean subroutine; // Temporarily stopped so a subroutine can run
|
||||
qboolean wait; // Execution paused until next frame
|
||||
qboolean legacy; // Backwards compatible with old console buffer
|
||||
qboolean ownvars; // Buffer has its own private local variables
|
||||
qboolean loop; // Buffer loops itself
|
||||
qboolean returning; // Buffer is returning a value
|
||||
|
||||
// Execution position
|
||||
enum {
|
||||
cmd_ready,
|
||||
cmd_tokenized,
|
||||
cmd_processed
|
||||
} position;
|
||||
|
||||
// Return value status
|
||||
enum {
|
||||
cmd_normal, // Normal status
|
||||
cmd_waiting, // Waiting for a return value
|
||||
cmd_returned // Return value available
|
||||
} returned;
|
||||
|
||||
// Stack
|
||||
struct cmd_buffer_s *prev, *next; // Neighboring buffers in stack
|
||||
|
@ -164,11 +184,13 @@ int Cmd_CheckParm (const char *parm);
|
|||
// Returns the position (1 to argc-1) in the command's argument list
|
||||
// where the given parameter apears, or 0 if not present
|
||||
|
||||
int Cmd_Process (void);
|
||||
void Cmd_TokenizeString (const char *text, qboolean legacy);
|
||||
// Takes a null terminated string. Does not need to be /n terminated.
|
||||
// breaks the string up into arg tokens.
|
||||
|
||||
void Cmd_ExecuteString (const char *text, cmd_source_t src);
|
||||
void Cmd_ExecuteParsed (cmd_source_t src);
|
||||
int Cmd_ExecuteString (const char *text, cmd_source_t src);
|
||||
// Parses a single line of text into arguments and tries to execute it.
|
||||
// The text can come from the command buffer, a remote client, or stdin.
|
||||
|
||||
|
@ -191,5 +213,6 @@ void Cmd_Return (const char *value);
|
|||
extern struct cvar_s *cmd_warncmd;
|
||||
|
||||
extern cmd_buffer_t *cmd_legacybuffer; // Allow access to the legacy buffer as an alternate console buffer
|
||||
extern cmd_buffer_t *cmd_keybindbuffer; // Allow access to dedicated key binds command buffer
|
||||
|
||||
#endif // __cmd_h
|
||||
|
|
294
libs/util/cmd.c
294
libs/util/cmd.c
|
@ -70,6 +70,7 @@ 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
|
||||
cmd_buffer_t *cmd_privatebuffer; // Buffer for internal command execution
|
||||
cmd_buffer_t *cmd_activebuffer; // Buffer currently being executed
|
||||
|
||||
cmd_buffer_t *cmd_recycled; // Recycled buffers
|
||||
|
@ -176,6 +177,8 @@ Cmd_NewBuffer (qboolean ownvars)
|
|||
new->locals = Hash_NewTable (512, Cmd_LocalGetKey, Cmd_LocalFree, 0);
|
||||
new->ownvars = ownvars;
|
||||
new->prev = new->next = 0;
|
||||
new->position = cmd_ready;
|
||||
new->returned = cmd_normal;
|
||||
return new;
|
||||
}
|
||||
|
||||
|
@ -190,7 +193,7 @@ void
|
|||
Cmd_FreeBuffer (cmd_buffer_t *free) {
|
||||
if (free->ownvars)
|
||||
Hash_DelTable(free->locals); // Local variables are always deadbeef
|
||||
free->wait = free->loop = free->ownvars = free->legacy = free->returning = free->imperative = false;
|
||||
free->wait = free->loop = free->ownvars = free->legacy = free->subroutine = false;
|
||||
dstring_clearstr (free->buffer);
|
||||
dstring_clearstr (free->line);
|
||||
dstring_clearstr (free->realline);
|
||||
|
@ -213,9 +216,11 @@ Cmd_FreeStack (cmd_buffer_t *stack) {
|
|||
|
||||
void
|
||||
Cmd_Return (const char *value) {
|
||||
dstring_clearstr (cmd_activebuffer->retval);
|
||||
dstring_appendstr (cmd_activebuffer->retval, value);
|
||||
cmd_activebuffer->returning = true;
|
||||
if (cmd_activebuffer->prev && cmd_activebuffer->prev->returned == cmd_waiting) {
|
||||
dstring_clearstr (cmd_activebuffer->prev->retval);
|
||||
dstring_appendstr (cmd_activebuffer->prev->retval, value);
|
||||
cmd_activebuffer->prev->returned = cmd_returned;
|
||||
}
|
||||
}
|
||||
|
||||
/*void
|
||||
|
@ -293,10 +298,8 @@ void
|
|||
Cmd_Wait_f (void)
|
||||
{
|
||||
cmd_buffer_t *cur;
|
||||
if (!cmd_activebuffer->imperative) {
|
||||
for (cur = cmd_activebuffer; cur; cur = cur->prev)
|
||||
cur->wait = true;
|
||||
}
|
||||
for (cur = cmd_activebuffer; cur; cur = cur->prev)
|
||||
cur->wait = true;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -328,6 +331,8 @@ Cbuf_Init (void)
|
|||
|
||||
cmd_legacybuffer = Cmd_NewBuffer (true);
|
||||
cmd_legacybuffer->legacy = true;
|
||||
|
||||
cmd_privatebuffer = Cmd_NewBuffer (true);
|
||||
|
||||
cmd_activebuffer = cmd_consolebuffer;
|
||||
|
||||
|
@ -447,11 +452,12 @@ Cbuf_ExecuteBuffer (cmd_buffer_t *buffer)
|
|||
{
|
||||
dstring_t *buf = dstring_newstr ();
|
||||
cmd_buffer_t *temp = cmd_activebuffer; // save old context
|
||||
int ret;
|
||||
|
||||
cmd_activebuffer = buffer;
|
||||
buffer->wait = false;
|
||||
while (1) {
|
||||
if (!strlen(buffer->buffer->str)) {
|
||||
if (!strlen(buffer->buffer->str) && buffer->position == cmd_ready) {
|
||||
if (buffer->loop) {
|
||||
if (cmd_maxloop->value && buffer->loop > cmd_maxloop->value) {
|
||||
Cmd_Error(va("GIB: Loop lasted longer than %i iterations, forcefully terminating.\n",
|
||||
|
@ -464,12 +470,28 @@ Cbuf_ExecuteBuffer (cmd_buffer_t *buffer)
|
|||
else
|
||||
break;
|
||||
}
|
||||
Cbuf_ExtractLine (buffer->buffer, buf, buffer->legacy);
|
||||
Cmd_ExecuteString (buf->str, src_command);
|
||||
if (buffer->wait)
|
||||
break;
|
||||
if (cmd_error)
|
||||
break;
|
||||
|
||||
if (buffer->position == cmd_ready) {
|
||||
Cbuf_ExtractLine (buffer->buffer, buf, buffer->legacy);
|
||||
Cmd_TokenizeString (buf->str, cmd_activebuffer->legacy);
|
||||
if (cmd_error)
|
||||
break;
|
||||
buffer->position = cmd_tokenized;
|
||||
}
|
||||
if (buffer->position == cmd_tokenized) {
|
||||
ret = Cmd_Process ();
|
||||
if (ret < 0)
|
||||
break;
|
||||
buffer->position = cmd_processed;
|
||||
}
|
||||
if (buffer->position == cmd_processed) {
|
||||
Cmd_ExecuteParsed (src_command);
|
||||
if (cmd_error)
|
||||
break;
|
||||
buffer->position = cmd_ready;
|
||||
if (buffer->wait || buffer->subroutine)
|
||||
break;
|
||||
}
|
||||
dstring_clearstr (buf);
|
||||
}
|
||||
dstring_delete (buf);
|
||||
|
@ -479,31 +501,31 @@ Cbuf_ExecuteBuffer (cmd_buffer_t *buffer)
|
|||
void
|
||||
Cbuf_ExecuteStack (cmd_buffer_t *buffer)
|
||||
{
|
||||
qboolean wait = false;
|
||||
cmd_buffer_t *cur, *temp;
|
||||
|
||||
cmd_error = false;
|
||||
|
||||
for (cur = buffer; cur->next; cur = cur->next);
|
||||
for (; cur != buffer; cur = temp) {
|
||||
for (;cur; cur = temp) {
|
||||
temp = cur->prev;
|
||||
Cbuf_ExecuteBuffer (cur);
|
||||
if (cur->wait) {
|
||||
wait = true;
|
||||
if (cmd_error || cur->wait)
|
||||
break;
|
||||
} else if (cmd_error)
|
||||
break;
|
||||
else {
|
||||
if (cur->subroutine) { // Something was added to the stack, follow it
|
||||
cur->subroutine = false;
|
||||
temp = cur->next;
|
||||
continue;
|
||||
}
|
||||
if (cur != buffer) {
|
||||
cur->prev->next = 0;
|
||||
Cmd_FreeBuffer (cur);
|
||||
}
|
||||
}
|
||||
if (!wait)
|
||||
Cbuf_ExecuteBuffer (buffer);
|
||||
if (cmd_error) {
|
||||
// If an error occured, nuke the entire stack
|
||||
// If an error occured nuke the stack
|
||||
Cmd_FreeStack (buffer->next);
|
||||
buffer->next = 0;
|
||||
buffer->position = cmd_ready;
|
||||
dstring_clearstr (buffer->buffer); // And the root buffer
|
||||
}
|
||||
}
|
||||
|
@ -533,18 +555,11 @@ Cbuf_Execute (void)
|
|||
void
|
||||
Cmd_ExecuteSubroutine (cmd_buffer_t *buffer)
|
||||
{
|
||||
// Inherit some flags from the current buffer
|
||||
|
||||
buffer->imperative = cmd_activebuffer->imperative;
|
||||
if (cmd_activebuffer->next)
|
||||
if (cmd_activebuffer->next) // Get rid of anything already there
|
||||
Cmd_FreeStack (cmd_activebuffer->next);
|
||||
cmd_activebuffer->next = buffer;
|
||||
cmd_activebuffer->next = buffer; // Link it in
|
||||
buffer->prev = cmd_activebuffer;
|
||||
Cbuf_ExecuteBuffer (buffer);
|
||||
/* if (!buffer->wait) {
|
||||
Cmd_FreeBuffer (buffer);
|
||||
cmd_activebuffer->next = 0;
|
||||
}*/
|
||||
cmd_activebuffer->subroutine = true; // Signal that a subroutine is beginning
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -808,7 +823,7 @@ Cmd_Argv (int arg)
|
|||
{
|
||||
if (arg >= cmd_activebuffer->argc)
|
||||
return "";
|
||||
if (cmd_activebuffer->argv[arg]->state == 1)
|
||||
if (cmd_activebuffer->argv[arg]->state == cmd_done)
|
||||
return cmd_activebuffer->argv[arg]->processed->str;
|
||||
else
|
||||
return cmd_activebuffer->argv[arg]->original->str;
|
||||
|
@ -938,7 +953,7 @@ Cmd_GetToken (const char *str, qboolean legacy)
|
|||
}
|
||||
|
||||
int Cmd_ProcessVariables (dstring_t * dstr);
|
||||
int Cmd_ProcessEmbedded (dstring_t * dstr);
|
||||
int Cmd_ProcessEmbedded (cmd_token_t *tok, dstring_t * dstr);
|
||||
|
||||
int tag_shift = 0;
|
||||
int tag_special = 0;
|
||||
|
@ -1064,9 +1079,12 @@ Cmd_ProcessIndex (dstring_t * dstr, int start)
|
|||
dstring_delete (value);
|
||||
return val;
|
||||
}
|
||||
if (!dstr->str[i])
|
||||
if (!dstr->str[i]) {
|
||||
Cmd_Error ("Unmatched bracket in index expression.\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
Cmd_Error ("Reached end of Cmd_ProcessIndex when I shouldn't have.\n");
|
||||
return -1; // Should never get here
|
||||
}
|
||||
|
||||
|
@ -1106,6 +1124,7 @@ Cmd_ProcessVariablesRecursive (dstring_t * dstr, int start)
|
|||
continue;
|
||||
}
|
||||
} else if (!dstr->str[i] && braces) { // No closing brace
|
||||
Cmd_Error ("Unmatched brace in variable substitution expression.\n");
|
||||
n = -1;
|
||||
break;
|
||||
} else if ((braces && dstr->str[i] == '}' && !escaped (dstr->str, i)) || (!braces && !isalnum((byte)dstr->str[i]) && dstr->str[i] != '_')) {
|
||||
|
@ -1151,51 +1170,49 @@ int
|
|||
Cmd_ProcessEmbeddedSingle (dstring_t * dstr, int start)
|
||||
{
|
||||
int n;
|
||||
cmd_buffer_t *temp;
|
||||
dstring_t *command, *retval;
|
||||
|
||||
dstring_t *command;
|
||||
cmd_buffer_t *sub;
|
||||
|
||||
n = Cmd_EndBrace (dstr->str+start+1)+1;
|
||||
if (n < 0) {
|
||||
Cmd_Error ("GIB: Unmatched brace in embedded command expression.\n");
|
||||
return n;
|
||||
return -1;
|
||||
}
|
||||
command = dstring_newstr ();
|
||||
dstring_insert (command, dstr->str + start + 2, n - 2, 0);
|
||||
temp = Cmd_NewBuffer (false);
|
||||
temp->imperative = true;
|
||||
temp->locals = cmd_activebuffer->locals;
|
||||
Cbuf_InsertTextTo (temp, command->str);
|
||||
Cbuf_ExecuteBuffer (temp);
|
||||
retval = 0;
|
||||
if (!cmd_error) {
|
||||
if (cmd_activebuffer->returned == cmd_waiting) {
|
||||
Cmd_Error ("Embedded command expression did not result in a return value.\n");
|
||||
return -1;
|
||||
}
|
||||
if (cmd_activebuffer->returned == cmd_returned) {
|
||||
dstring_snip(dstr, start, n+1);
|
||||
if (temp->returning) // Top buffer returned a value (likely a builtin function)
|
||||
retval = temp->retval;
|
||||
else if (temp->next && temp->next->returning) // Next buffer returned a value (an alias or config file)
|
||||
retval = temp->next->retval;
|
||||
else {
|
||||
Cmd_Error ("GIB: Embedded command expression resulted in no return value.\n");
|
||||
n = -1;
|
||||
}
|
||||
if (retval) {
|
||||
dstring_insertstr (dstr, retval->str, start);
|
||||
n = strlen(retval->str);
|
||||
}
|
||||
dstring_insertstr (dstr, cmd_activebuffer->retval->str, start);
|
||||
n = strlen(cmd_activebuffer->retval->str);
|
||||
cmd_activebuffer->returned = cmd_normal;
|
||||
} else {
|
||||
command = dstring_newstr ();
|
||||
sub = Cmd_NewBuffer (false);
|
||||
sub->locals = cmd_activebuffer->locals;
|
||||
dstring_insert (command, dstr->str + start + 2, n - 2, 0);
|
||||
Cbuf_InsertTextTo (sub, command->str);
|
||||
Cmd_ExecuteSubroutine (sub);
|
||||
cmd_activebuffer->returned = cmd_waiting;
|
||||
n = -2;
|
||||
dstring_delete (command);
|
||||
}
|
||||
Cmd_FreeStack (temp);
|
||||
dstring_delete (command);
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
Cmd_ProcessEmbedded (dstring_t * dstr)
|
||||
Cmd_ProcessEmbedded (cmd_token_t *tok, dstring_t * dstr)
|
||||
{
|
||||
int i, n;
|
||||
|
||||
for (i = 0; i < strlen(dstr->str); i++) {
|
||||
for (i = tok->pos; i < strlen(dstr->str); i++) {
|
||||
if (dstr->str[i] == '~' && dstr->str[i+1] == '{') {
|
||||
n = Cmd_ProcessEmbeddedSingle (dstr, i);
|
||||
if (n == -2) {
|
||||
tok->pos = i;
|
||||
return n;
|
||||
}
|
||||
if (n < 0)
|
||||
return n;
|
||||
else
|
||||
|
@ -1248,6 +1265,7 @@ Cmd_ProcessMath (dstring_t * dstr)
|
|||
}
|
||||
if (paren) {
|
||||
ret = -1;
|
||||
Cmd_Error ("Unmatched parenthesis in math expression.\n");
|
||||
break;
|
||||
}
|
||||
/* Copy text between parentheses into a buffer */
|
||||
|
@ -1307,31 +1325,67 @@ Cmd_ProcessToken (cmd_token_t *token)
|
|||
dstring_appendstr (token->processed, token->original->str);
|
||||
|
||||
Cmd_ProcessTags (token->processed);
|
||||
res = Cmd_ProcessEmbedded (token->processed);
|
||||
res = Cmd_ProcessEmbedded (token, token->processed);
|
||||
if (res < 0)
|
||||
return res;
|
||||
res = Cmd_ProcessVariables (token->processed);
|
||||
if (res < 0) {
|
||||
Cmd_Error ("Parse error: Unmatched braces in "
|
||||
"variable substitution expression.\n");
|
||||
if (res < 0)
|
||||
return res;
|
||||
}
|
||||
res = Cmd_ProcessMath (token->processed);
|
||||
if (res == -1) {
|
||||
Cmd_Error ("Parse error: Unmatched parenthesis\n");
|
||||
if (res < 0)
|
||||
return res;
|
||||
}
|
||||
if (res == -2) {
|
||||
return res;
|
||||
}
|
||||
Cmd_ProcessEscapes (token->processed);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Cmd_Process
|
||||
|
||||
Processes all tokens that need to be processed
|
||||
*/
|
||||
|
||||
int
|
||||
Cmd_Process (void)
|
||||
{
|
||||
int arg, res, i;
|
||||
const char *str;
|
||||
|
||||
for (arg = 0; arg < cmd_activebuffer->argc; arg++) {
|
||||
if (cmd_activebuffer->argv[arg]->state == cmd_process) {
|
||||
res = Cmd_ProcessToken (cmd_activebuffer->argv[arg]);
|
||||
if (res < 0)
|
||||
return res;
|
||||
cmd_activebuffer->argv[arg]->state = cmd_done;
|
||||
}
|
||||
}
|
||||
dstring_clearstr (cmd_activebuffer->line);
|
||||
for (arg = 0; arg < cmd_activebuffer->argc; arg++) {
|
||||
if (cmd_activebuffer->argv[arg]->state == cmd_done)
|
||||
str = cmd_activebuffer->argv[arg]->processed->str;
|
||||
else
|
||||
str = cmd_activebuffer->argv[arg]->original->str;
|
||||
for (i = 0; i < cmd_activebuffer->argv[arg]->space; i++)
|
||||
dstring_appendstr (cmd_activebuffer->line, " ");
|
||||
cmd_activebuffer->args[arg] = strlen(cmd_activebuffer->line->str);
|
||||
if (cmd_activebuffer->argv[arg]->delim == '\'' ||
|
||||
cmd_activebuffer->argv[arg]->delim == '\"')
|
||||
dstring_appendstr (cmd_activebuffer->line, va("%c", cmd_activebuffer->argv[arg]->delim));
|
||||
if (cmd_activebuffer->argv[arg]->delim == '{')
|
||||
dstring_appendstr (cmd_activebuffer->line, "{");
|
||||
dstring_appendstr (cmd_activebuffer->line, str);
|
||||
if (cmd_activebuffer->argv[arg]->delim == '\'' ||
|
||||
cmd_activebuffer->argv[arg]->delim == '\"')
|
||||
dstring_appendstr (cmd_activebuffer->line, va("%c", cmd_activebuffer->argv[arg]->delim));
|
||||
if (cmd_activebuffer->argv[arg]->delim == '{')
|
||||
dstring_appendstr (cmd_activebuffer->line, "}");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
Cmd_TokenizeString (const char *text, qboolean legacy)
|
||||
{
|
||||
int i = 0, len = 0, quotes, braces, space, res;
|
||||
int i = 0, len = 0, quotes, braces, space;
|
||||
const char *str = text;
|
||||
unsigned int cmd_argc = 0;
|
||||
cmd_function_t *cmd;
|
||||
|
@ -1349,7 +1403,7 @@ Cmd_TokenizeString (const char *text, qboolean legacy)
|
|||
dstring_clearstr (cmd_activebuffer->line);
|
||||
while (strlen (str + i)) {
|
||||
if (!legacy && cmd_argc == 1) { // See if command wants unprocessed tokens
|
||||
cmd = (cmd_function_t *) Hash_Find (cmd_hash, cmd_activebuffer->argv[0]->processed->str);
|
||||
cmd = (cmd_function_t *) Hash_Find (cmd_hash, cmd_activebuffer->argv[0]->original->str);
|
||||
if (cmd && cmd->pure)
|
||||
process = false;
|
||||
}
|
||||
|
@ -1358,7 +1412,6 @@ Cmd_TokenizeString (const char *text, qboolean legacy)
|
|||
i++;
|
||||
space++;
|
||||
}
|
||||
dstring_appendsubstr (cmd_activebuffer->line, str + i - space, space);
|
||||
len = Cmd_GetToken (str + i, legacy);
|
||||
if (len < 0) {
|
||||
Cmd_Error ("Parse error: Unmatched quotes, braces, or "
|
||||
|
@ -1384,9 +1437,10 @@ Cmd_TokenizeString (const char *text, qboolean legacy)
|
|||
/* Remove surrounding quotes or double quotes or braces */
|
||||
quotes = 0;
|
||||
braces = 0;
|
||||
cmd_activebuffer->args[cmd_argc - 1] = strlen (cmd_activebuffer->line->str);
|
||||
cmd_activebuffer->argv[cmd_argc-1]->delim = ' ';
|
||||
if ((str[i] == '\'' && str[i + len] == '\'')
|
||||
|| (str[i] == '"' && str[i + len] == '"')) {
|
||||
cmd_activebuffer->argv[cmd_argc-1]->delim = str[i];
|
||||
dstring_appendsubstr (cmd_activebuffer->line, str + i, 1);
|
||||
dstring_appendsubstr (cmd_activebuffer->line, str + i, 1);
|
||||
i++;
|
||||
|
@ -1397,25 +1451,15 @@ Cmd_TokenizeString (const char *text, qboolean legacy)
|
|||
i++;
|
||||
len -= 1;
|
||||
braces = 1;
|
||||
cmd_activebuffer->argv[cmd_argc-1]->delim = '{';
|
||||
}
|
||||
dstring_insert (cmd_activebuffer->argv[cmd_argc-1]->original, str + i, len, 0);
|
||||
if (!legacy && !braces && process && text[0] != '|') {
|
||||
res = Cmd_ProcessToken (cmd_activebuffer->argv[cmd_argc-1]);
|
||||
if (res < 0) {
|
||||
cmd_activebuffer->argc = 0;
|
||||
return;
|
||||
}
|
||||
cmd_activebuffer->argv[cmd_argc-1]->state = 1;
|
||||
dstring_insertstr (cmd_activebuffer->line,
|
||||
cmd_activebuffer->argv[cmd_argc-1]->processed->str,
|
||||
strlen (cmd_activebuffer->line->str) - quotes);
|
||||
}
|
||||
else {
|
||||
cmd_activebuffer->argv[cmd_argc-1]->state = 0;
|
||||
dstring_insertstr (cmd_activebuffer->line,
|
||||
cmd_activebuffer->argv[cmd_argc-1]->original->str,
|
||||
strlen (cmd_activebuffer->line->str) - quotes);
|
||||
}
|
||||
if (!legacy && !braces && process && text[0] != '|')
|
||||
cmd_activebuffer->argv[cmd_argc-1]->state = cmd_process;
|
||||
else
|
||||
cmd_activebuffer->argv[cmd_argc-1]->state = cmd_original;
|
||||
cmd_activebuffer->argv[cmd_argc-1]->pos = 0;
|
||||
cmd_activebuffer->argv[cmd_argc-1]->space = space;
|
||||
i += len + quotes + braces; /* If we ended on a quote or brace,
|
||||
skip it */
|
||||
}
|
||||
|
@ -1679,20 +1723,18 @@ Cmd_CompleteAliasBuildList (const char *partial)
|
|||
}
|
||||
|
||||
/*
|
||||
Cmd_ExecuteString
|
||||
Cmd_ExecuteParsed
|
||||
|
||||
A complete command line has been parsed, so try to execute it
|
||||
*/
|
||||
void
|
||||
Cmd_ExecuteString (const char *text, cmd_source_t src)
|
||||
Cmd_ExecuteParsed (cmd_source_t src)
|
||||
{
|
||||
cmd_function_t *cmd;
|
||||
cmdalias_t *a;
|
||||
|
||||
cmd_source = src;
|
||||
|
||||
Cmd_TokenizeString (text, cmd_activebuffer->legacy);
|
||||
|
||||
// execute the command line
|
||||
if (!Cmd_Argc ())
|
||||
return; // no tokens
|
||||
|
@ -1738,7 +1780,6 @@ Cmd_ExecuteString (const char *text, cmd_source_t src)
|
|||
for (i = 0; i < Cmd_Argc (); i++)
|
||||
Cmd_SetLocal (sub, va ("%i", i), Cmd_Argv (i), -1);
|
||||
Cmd_SetLocal (sub, "argn", va ("%i", Cmd_Argc ()), -1);
|
||||
// This will handle freeing the buffer for us, leave it alone
|
||||
Cmd_ExecuteSubroutine (sub);
|
||||
return;
|
||||
}
|
||||
|
@ -1747,6 +1788,26 @@ Cmd_ExecuteString (const char *text, cmd_source_t src)
|
|||
Sys_Printf ("Unknown command \"%s\"\n", Cmd_Argv (0));
|
||||
}
|
||||
|
||||
int Cmd_ExecuteString (const char *text, cmd_source_t src)
|
||||
{
|
||||
cmd_buffer_t *old = cmd_activebuffer; // Save context
|
||||
int ret;
|
||||
cmd_activebuffer = cmd_privatebuffer;
|
||||
Cmd_TokenizeString (text, cmd_activebuffer->legacy);
|
||||
if (!Cmd_Argc()) {
|
||||
cmd_activebuffer = old;
|
||||
return -1;
|
||||
}
|
||||
ret = Cmd_Process ();
|
||||
if (ret < 0) {
|
||||
cmd_activebuffer = old;
|
||||
return ret;
|
||||
}
|
||||
Cmd_ExecuteParsed (src);
|
||||
cmd_activebuffer = old;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Cmd_CheckParm
|
||||
|
||||
|
@ -1901,26 +1962,27 @@ Cmd_Break_f (void) {
|
|||
|
||||
void
|
||||
Cmd_Return_f (void) {
|
||||
if (Cmd_Argc() > 2) {
|
||||
int argc = Cmd_Argc();
|
||||
const char *val = Cmd_Argv(1);
|
||||
cmd_buffer_t *old = cmd_activebuffer; // save context
|
||||
if (argc > 2) {
|
||||
Cmd_Error("GIB: Invalid return statement. Return takes either one argument or none.\n");
|
||||
return;
|
||||
}
|
||||
while (cmd_activebuffer->loop) { // We need to get out of any loops
|
||||
dstring_clearstr(cmd_activebuffer->buffer);
|
||||
cmd_activebuffer->loop = false;
|
||||
cmd_activebuffer = cmd_activebuffer->prev;
|
||||
}
|
||||
if (!cmd_activebuffer->prev) {
|
||||
Cmd_Error("GIB: Return attempted in a root buffer\n");
|
||||
return;
|
||||
}
|
||||
while (cmd_activebuffer->loop) // We need to get out of any loops
|
||||
cmd_activebuffer = cmd_activebuffer->prev;
|
||||
if (cmd_activebuffer->next) {
|
||||
Cmd_FreeStack (cmd_activebuffer->next);
|
||||
cmd_activebuffer->next = 0;
|
||||
}
|
||||
dstring_clearstr (cmd_activebuffer->buffer); // Clear the buffer out no matter what
|
||||
if (Cmd_Argc() == 2) {
|
||||
dstring_clearstr (cmd_activebuffer->retval);
|
||||
dstring_appendstr (cmd_activebuffer->retval, Cmd_Argv(1));
|
||||
cmd_activebuffer->returning = true;
|
||||
}
|
||||
cmd_activebuffer = cmd_activebuffer->prev;
|
||||
if (argc == 2)
|
||||
Cmd_Return (val);
|
||||
cmd_activebuffer = old;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
Loading…
Reference in a new issue