Beautified GIB, improved looping and backtraces slightly. Old buffers are

now recycled, not freed.  Fixed some bugs in exp.c.  Ready to add embeded
functions (read: function calls with return values) and for loops.
Probably some other misc. fixes, I tend to go on debugging streaks.
This commit is contained in:
Brian Koropoff 2002-03-27 06:24:19 +00:00
parent 807e7de22e
commit 676bf39d9d
5 changed files with 161 additions and 76 deletions

View file

@ -43,7 +43,8 @@ typedef struct cmd_buffer_s {
qboolean ownvars; // Buffer has its own private local variables
qboolean loop; // Buffer is in a loop
unsigned int argc, maxargc; // Number of args, number of args allocated
struct dstring_s **argv; // Array of arguments
struct dstring_s **argv; // Array of processed tokens
struct dstring_s **argu; // Array of unprocessed tokens
struct dstring_s *realline; // Actual command being processed
struct dstring_s *line; // Tokenized and reassembled command
struct dstring_s *looptext; // If a looping buffer, the text we are looping on
@ -149,7 +150,7 @@ 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
void Cmd_TokenizeString (const char *text, qboolean filter);
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.

View file

@ -72,12 +72,14 @@ cmd_buffer_t *cmd_legacybuffer; // Server stuffcmd buffer with
// absolute backwards-compatibility
cmd_buffer_t *cmd_activebuffer; // Buffer currently being executed
cmd_buffer_t *cmd_recycled; // Recycled buffers
dstring_t *cmd_backtrace;
qboolean cmd_error;
cvar_t *cmd_warncmd;
cvar_t *cmd_highchars;
cvar_t *cmd_maxloop;
hashtab_t *cmd_alias_hash;
hashtab_t *cmd_hash;
@ -138,19 +140,46 @@ Cmd_NewBuffer (qboolean ownvars)
{
cmd_buffer_t *new;
if (cmd_recycled) { // If we have old buffers lying around
new = cmd_recycled;
cmd_recycled = new->next;
}
else {
new = calloc (1, sizeof (cmd_buffer_t));
new->buffer = dstring_newstr ();
new->line = dstring_newstr ();
new->realline = dstring_newstr ();
new->looptext = dstring_newstr ();
}
if (ownvars)
new->locals = Hash_NewTable (1021, Cmd_LocalGetKey, Cmd_LocalFree, 0);
new->locals = Hash_NewTable (512, Cmd_LocalGetKey, Cmd_LocalFree, 0);
new->ownvars = ownvars;
new->prev = new->next = 0;
return new;
}
/*
Cmd_FreeBuffer
Actually just "recycles" buffer for
later use
*/
void
Cmd_FreeBuffer (cmd_buffer_t *free) {
if (free->ownvars)
Hash_DelTable(free->locals); // Local variables are dead, period
free->wait = free->loop = free->ownvars = free->legacy = false;
dstring_clearstr (free->buffer);
dstring_clearstr (free->line);
dstring_clearstr (free->realline);
dstring_clearstr (free->looptext);
free->locals = 0;
free->next = cmd_recycled;
cmd_recycled = free;
}
/*void
Cmd_FreeBuffer (cmd_buffer_t *del)
{
int i;
@ -158,18 +187,23 @@ Cmd_FreeBuffer (cmd_buffer_t *del)
dstring_delete (del->buffer);
dstring_delete (del->line);
dstring_delete (del->realline);
dstring_delete (del->looptext);
if (del->maxargc) {
for (i = 0; i < del->maxargc; i++)
for (i = 0; i < del->maxargc; i++) {
if (del->argv[i])
dstring_delete (del->argv[i]);
if (del->argu[i])
dstring_delete (del->argu[i]);
}
free (del->argv);
free (del->argu);
}
if (del->args)
free(del->args);
if (del->ownvars)
Hash_DelTable(del->locals);
free(del);
}
}*/
/* Quick function to determine if a character is escaped */
qboolean
@ -194,6 +228,7 @@ escape (dstring_t * dstr)
switch (dstr->str[i]) {
case '\\':
case '$':
case '#':
case '{':
case '}':
case '\"':
@ -236,8 +271,11 @@ Cmd_Error (const char *message)
dstring_clearstr (cmd_backtrace);
dstring_appendstr (cmd_backtrace, message);
dstring_appendstr (cmd_backtrace, "Path of execution:\n");
for (cur = cmd_activebuffer; cur; cur = cur->prev)
for (cur = cmd_activebuffer; cur; cur = cur->prev) {
if (cmd_activebuffer->loop) // Skip loop buffers, they are not 'real'
continue;
dstring_appendstr (cmd_backtrace, va ("--> %s\n", cur->realline->str));
}
}
@ -255,6 +293,8 @@ Cbuf_Init (void)
cmd_activebuffer = cmd_consolebuffer;
cmd_recycled = 0;
cmd_backtrace = dstring_newstr ();
}
@ -306,25 +346,25 @@ Cbuf_InsertText (const char *text)
*/
void
extract_line (dstring_t * buffer, dstring_t * line)
extract_line (dstring_t * buffer, dstring_t * line, qboolean legacy)
{
int i, squotes = 0, dquotes = 0, braces = 0, n;
char *tmp;
for (i = 0; buffer->str[i]; i++) {
if (buffer->str[i] == '\'' && !escaped (buffer->str, i)
&& !dquotes && !braces)
if (!legacy && buffer->str[i] == '\'' && !escaped (buffer->str, i)
&& !dquotes)
squotes ^= 1;
if (buffer->str[i] == '"' && !escaped (buffer->str, i)
&& !squotes && !braces)
&& !squotes)
dquotes ^= 1;
if (buffer->str[i] == ';' && !escaped (buffer->str, i)
&& !squotes && !dquotes && !braces)
break;
if (buffer->str[i] == '{' && !escaped (buffer->str, i)
if (!legacy && buffer->str[i] == '{' && !escaped (buffer->str, i)
&& !squotes && !dquotes)
braces++;
if (buffer->str[i] == '}' && !escaped (buffer->str, i)
if (!legacy && buffer->str[i] == '}' && !escaped (buffer->str, i)
&& !squotes && !dquotes)
braces--;
if (buffer->str[i] == '/' && buffer->str[i + 1] == '/'
@ -372,15 +412,21 @@ Cbuf_ExecuteBuffer (cmd_buffer_t *buffer)
cmd_activebuffer = buffer;
buffer->wait = false;
cmd_error = false;
while (1) {
if (!strlen(buffer->buffer->str)) {
if (buffer->loop)
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",
(int)cmd_maxloop->value));
break;
}
Cbuf_InsertTextTo(buffer, buffer->looptext->str);
buffer->loop++;
}
else
break;
}
extract_line (buffer->buffer, buf);
extract_line (buffer->buffer, buf, buffer->legacy);
Cmd_ExecuteString (buf->str, src_command);
if (buffer->wait)
break;
@ -398,6 +444,8 @@ Cbuf_ExecuteStack (cmd_buffer_t *buffer)
qboolean wait = false;
cmd_buffer_t *cur;
cmd_error = false;
for (cur = buffer; cur->next; cur = cur->next);
for (; cur != buffer; cur = cur->prev) {
Cbuf_ExecuteBuffer (cur);
@ -465,7 +513,7 @@ Cbuf_Execute_Sets (void)
dstring_t *buf = dstring_newstr ();
while (strlen (cmd_consolebuffer->buffer->str)) {
extract_line (cmd_consolebuffer->buffer, buf);
extract_line (cmd_consolebuffer->buffer, buf, cmd_consolebuffer->legacy);
if (!strncmp (buf->str, "set", 3) && isspace ((int) buf->str[3])) {
Cmd_ExecuteString (buf->str, src_command);
} else if (!strncmp (buf->str, "setrom", 6)
@ -710,6 +758,14 @@ Cmd_Argv (int arg)
return cmd_activebuffer->argv[arg]->str;
}
const char *
Cmd_Argu (int arg)
{
if (arg >= cmd_activebuffer->argc)
return "";
return cmd_activebuffer->argu[arg]->str;
}
/*
Cmd_Args
@ -779,26 +835,24 @@ Cmd_EndBrace (const char *str)
}
int
Cmd_GetToken (const char *str)
Cmd_GetToken (const char *str, qboolean legacy)
{
int i;
switch (*str) {
case '\'':
if (!legacy) {
if (*str == '\'')
return Cmd_EndSingleQuote (str);
case '\"':
return Cmd_EndDoubleQuote (str);
case '{':
if (*str == '{')
return Cmd_EndBrace (str);
case '}':
if (*str == '}')
return -1;
default:
}
if (*str == '\"')
return Cmd_EndDoubleQuote (str);
for (i = 0; i < strlen (str); i++)
if (isspace (str[i]))
break;
return i;
}
return -1; // We should never get here
}
int tag_shift = 0;
@ -921,13 +975,14 @@ Cmd_ProcessVariablesRecursive (dstring_t * dstr, int start)
dstring_t *varname;
cmd_localvar_t *lvar;
cvar_t *cvar;
int i, n;
int i, n, braces = 0;
varname = dstring_newstr ();
for (i = start + 2;; i++) {
if (dstr->str[i] == '$' && dstr->str[i + 1] == '{'
&& !escaped (dstr->str, i)) {
if (dstr->str[start+1] == '{')
braces = 1;
for (i = start + 1 + braces;; i++) {
if (dstr->str[i] == '$' && (braces || dstr->str[i+1] == '{') && !escaped (dstr->str, i)) {
n = Cmd_ProcessVariablesRecursive (dstr, i);
if (n < 0) {
break;
@ -935,7 +990,7 @@ Cmd_ProcessVariablesRecursive (dstring_t * dstr, int start)
i += n - 1;
continue;
}
} else if (dstr->str[i] == '}' && !escaped (dstr->str, i)) {
} else if (braces && dstr->str[i] == '}' && !escaped (dstr->str, i)) {
dstring_clearstr (varname);
dstring_insert (varname, dstr->str + start + 2, i - start - 2, 0);
// Nuke it, even if no match is found
@ -954,9 +1009,28 @@ Cmd_ProcessVariablesRecursive (dstring_t * dstr, int start)
} else
n = 0;
break;
} else if (!dstr->str[i]) { // No closing brace
} else if (!dstr->str[i] && braces) { // No closing brace
n = -1;
break;
} else if (!braces && !isalnum(dstr->str[i]) && dstr->str[i] != '_') {
dstring_clearstr (varname);
dstring_insert (varname, dstr->str + start + 1, i - start - 1, 0);
// Nuke it, even if no match is found
dstring_snip (dstr, start, i - start);
lvar = (cmd_localvar_t *) Hash_Find (cmd_activebuffer->locals,
varname->str);
if (lvar) {
// Local variables get precedence
dstring_insertstr (dstr, lvar->value->str, start);
n = strlen (lvar->value->str);
} else if ((cvar = Cvar_FindVar (varname->str))) {
// Then cvars
// Stick in the value of variable
dstring_insertstr (dstr, cvar->string, start);
n = strlen (cvar->string);
} else
n = 0;
break;
}
}
dstring_delete (varname);
@ -969,8 +1043,7 @@ Cmd_ProcessVariables (dstring_t * dstr)
int i, n;
for (i = 0; i < strlen (dstr->str); i++) {
if (dstr->str[i] == '$' && dstr->str[i + 1] == '{'
&& !escaped (dstr->str, i)) {
if (dstr->str[i] == '$' && !escaped (dstr->str, i)) {
n = Cmd_ProcessVariablesRecursive (dstr, i);
if (n < 0)
return n;
@ -993,7 +1066,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 (dstr->str[i] == '#' && dstr->str[i + 1] == '('
&& !escaped (dstr->str, i)) {
paren = 1;
for (n = 2;; n++) {
@ -1076,7 +1149,7 @@ Cmd_ProcessEscapes (dstring_t * dstr)
*/
void
Cmd_TokenizeString (const char *text, qboolean filter)
Cmd_TokenizeString (const char *text, qboolean legacy)
{
int i = 0, len = 0, quotes, braces, space, res;
const char *str = text;
@ -1099,7 +1172,7 @@ Cmd_TokenizeString (const char *text, qboolean filter)
space++;
}
dstring_appendsubstr (cmd_activebuffer->line, str + i - space, space);
len = Cmd_GetToken (str + i);
len = Cmd_GetToken (str + i, legacy);
if (len < 0) {
Cmd_Error ("Parse error: Unmatched quotes, braces, or "
"double quotes\n");
@ -1113,14 +1186,20 @@ Cmd_TokenizeString (const char *text, qboolean filter)
sizeof (dstring_t *) * cmd_argc);
SYS_CHECKMEM (cmd_activebuffer->argv);
cmd_activebuffer->argu = realloc (cmd_activebuffer->argu,
sizeof (dstring_t *) * cmd_argc);
SYS_CHECKMEM (cmd_activebuffer->argu);
cmd_activebuffer->args = realloc (cmd_activebuffer->args,
sizeof (int) * cmd_argc);
SYS_CHECKMEM (cmd_activebuffer->args);
cmd_activebuffer->argv[cmd_argc - 1] = dstring_newstr ();
cmd_activebuffer->argu[cmd_argc - 1] = dstring_newstr ();
cmd_activebuffer->maxargc++;
}
dstring_clearstr (cmd_activebuffer->argv[cmd_argc - 1]);
dstring_clearstr (cmd_activebuffer->argu[cmd_argc - 1]);
/* Remove surrounding quotes or double quotes or braces */
quotes = 0;
braces = 0;
@ -1139,8 +1218,8 @@ Cmd_TokenizeString (const char *text, qboolean filter)
braces = 1;
}
dstring_insert (cmd_activebuffer->argv[cmd_argc - 1], str + i, len, 0);
if (filter && text[0] != '|') {
if (!braces) {
dstring_insert (cmd_activebuffer->argu[cmd_argc - 1], str + i, len, 0);
if (!legacy && text[0] != '|' && !braces) {
Cmd_ProcessTags (cmd_activebuffer->argv[cmd_argc - 1]);
res =
Cmd_ProcessVariables (cmd_activebuffer->argv[cmd_argc - 1]);
@ -1160,7 +1239,6 @@ Cmd_TokenizeString (const char *text, qboolean filter)
cmd_activebuffer->argc = 0;
return;
}
}
Cmd_ProcessEscapes (cmd_activebuffer->argv[cmd_argc - 1]);
}
dstring_insertstr (cmd_activebuffer->line,
@ -1412,7 +1490,7 @@ Cmd_ExecuteString (const char *text, cmd_source_t src)
cmd_source = src;
Cmd_TokenizeString (text, !cmd_activebuffer->legacy);
Cmd_TokenizeString (text, cmd_activebuffer->legacy);
// execute the command line
if (!Cmd_Argc ())
@ -1438,7 +1516,7 @@ Cmd_ExecuteString (const char *text, cmd_source_t src)
Cbuf_InsertTextTo (sub, a->value);
for (i = 0; i < Cmd_Argc (); i++)
Cmd_SetLocal (sub, va ("%i", i), Cmd_Argv (i));
Cmd_SetLocal (sub, "#", va ("%i", Cmd_Argc ()));
Cmd_SetLocal (sub, "argn", va ("%i", Cmd_Argc ()));
// This will handle freeing the buffer for us, leave it alone
Cmd_ExecuteSubroutine (sub);
return;
@ -1561,7 +1639,7 @@ Cmd_While_f (void) {
sub = Cmd_NewBuffer (false);
sub->locals = cmd_activebuffer->locals; // Use current local variables
sub->loop = true;
dstring_appendstr (sub->looptext, va("ifnot '%s' {break;};\n", Cmd_Argv(1)));
dstring_appendstr (sub->looptext, va("ifnot '%s' break\n", Cmd_Argu(1)));
dstring_appendstr (sub->looptext, Cmd_Argv(2));
Cmd_ExecuteSubroutine (sub);
return;
@ -1663,6 +1741,7 @@ Cmd_Init (void)
Cmd_AddCommand ("cmdlist", Cmd_CmdList_f, "List all commands");
Cmd_AddCommand ("help", Cmd_Help_f, "Display help for a command or "
"variable");
Cmd_AddCommand ("if", Cmd_If_f, "Conditionally execute a set of commands.");
Cmd_AddCommand ("ifnot", Cmd_If_f, "Conditionally execute a set of commands if the condition is false.");
Cmd_AddCommand ("while", Cmd_While_f, "Execute a set of commands while a condition is true.");
@ -1673,6 +1752,9 @@ Cmd_Init (void)
// "alias and command hash tables");
cmd_warncmd = Cvar_Get ("cmd_warncmd", "0", CVAR_NONE, NULL, "Toggles the "
"display of error messages for unknown commands");
cmd_maxloop = Cvar_Get ("cmd_maxloop", "0", CVAR_NONE, NULL, "Controls the "
"maximum number of iterations a loop in GIB can do "
"before being forcefully terminated. 0 is infinite.");
}
char *com_token;

View file

@ -31,8 +31,8 @@ exp_error_t EXP_ERROR;
optable_t optable[] =
{
{"**", OP_Exp},
{"*", OP_Mult},
{"/", OP_Div},
{"*", OP_Mult},
{"+", OP_Add},
{"-", OP_Sub},
{"==", OP_Eq},
@ -274,6 +274,8 @@ exp_error_t EXP_Validate (token *chain)
else
return EXP_E_SYNTAX; /* Operator misuse */
}
else if (cur->generic.type == TOKEN_OP && cur->generic.next->generic.type == TOKEN_CPAREN)
return EXP_E_SYNTAX; /* Missing operand */
else if (cur->generic.type == TOKEN_NUM && cur->generic.next->generic.type == TOKEN_NUM)
return EXP_E_SYNTAX; /* Double number error */
else if (cur->generic.type == TOKEN_OPAREN && cur->generic.next->generic.type == TOKEN_CPAREN)

View file

@ -513,7 +513,7 @@ SVC_Status (void)
return;
con_printf_no_log = 1;
Cmd_TokenizeString ("status", false);
Cmd_TokenizeString ("status", true);
SV_BeginRedirect (RD_PACKET);
SV_Printf ("%s\n", Info_MakeString (svs.info, 0));
for (i = 0; i < MAX_CLIENTS; i++) {
@ -1027,7 +1027,7 @@ SV_ConnectionlessPacket (void)
s = MSG_ReadString (net_message);
Cmd_TokenizeString (s, false);
Cmd_TokenizeString (s, true);
c = Cmd_Argv (0);

View file

@ -1240,7 +1240,7 @@ SV_ExecuteUserCommand (const char *s)
ucmd_t *u;
ucmd_t cmd;
Cmd_TokenizeString (s, false);
Cmd_TokenizeString (s, true);
sv_player = host_client->edict;
cmd.name = Cmd_Argv(0);