mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-17 22:50:51 +00:00
A few GIB bugfixes, cleanups, and enhancements. Still more to come.
This commit is contained in:
parent
06cd013fc6
commit
1f5cabcba9
10 changed files with 112 additions and 103 deletions
|
@ -55,11 +55,10 @@ typedef struct cbuf_s {
|
|||
CBUF_STATE_NORMAL = 0, // Normal condition
|
||||
CBUF_STATE_WAIT, // Buffer is stalled until next frame
|
||||
CBUF_STATE_ERROR, // An unrecoverable error occured
|
||||
CBUF_STATE_STACK, // A buffer has been added to the stack
|
||||
CBUF_STATE_DONE, // This buffer has completed execution
|
||||
} state;
|
||||
CBUF_STATE_STACK // A buffer has been added to the stack
|
||||
} state;
|
||||
|
||||
qboolean strict; // Should we tolerate unknown commands
|
||||
qboolean strict; // Should we tolerate unknown commands?
|
||||
double resumetime; // Time when stack can be executed again
|
||||
|
||||
void *data; // Pointer to interpreter data
|
||||
|
@ -72,7 +71,6 @@ typedef struct cbuf_interpreter_s {
|
|||
void (*insert) (struct cbuf_s *cbuf, const char *str);
|
||||
void (*execute) (struct cbuf_s *cbuf);
|
||||
void (*execute_sets) (struct cbuf_s *cbuf);
|
||||
void (*reset) (struct cbuf_s *cbuf);
|
||||
} cbuf_interpreter_t;
|
||||
|
||||
extern cbuf_t *cbuf_active;
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
typedef struct gib_buffer_data_s {
|
||||
struct gib_tree_s *program, *ip;
|
||||
struct dstring_s *arg_composite;
|
||||
qboolean done, waitret, haveret;
|
||||
qboolean done, waitret;
|
||||
struct gib_sstack_s {
|
||||
struct gib_dsarray_s {
|
||||
struct dstring_s **dstrs;
|
||||
|
@ -53,7 +53,6 @@ typedef struct gib_buffer_data_s {
|
|||
|
||||
void GIB_Buffer_Construct (struct cbuf_s *cbuf);
|
||||
void GIB_Buffer_Destruct (struct cbuf_s *cbuf);
|
||||
void GIB_Buffer_Reset (struct cbuf_s *cbuf);
|
||||
void GIB_Buffer_Add (cbuf_t *cbuf, const char *str);
|
||||
void GIB_Buffer_Insert (cbuf_t *cbuf, const char *str);
|
||||
void GIB_Buffer_Push_Sstack (struct cbuf_s *cbuf);
|
||||
|
|
|
@ -47,6 +47,7 @@ typedef struct gib_domain_s {
|
|||
|
||||
gib_var_t *GIB_Var_Get (hashtab_t *first, hashtab_t *second, const char *key);
|
||||
gib_var_t *GIB_Var_Get_Complex (hashtab_t **first, hashtab_t **second, char *key, unsigned int *ind, qboolean create);
|
||||
void GIB_Var_Assign (gib_var_t *var, unsigned int index, dstring_t **values, unsigned int numv);
|
||||
hashtab_t *GIB_Domain_Get (const char *name);
|
||||
|
||||
void GIB_Var_Init (void);
|
||||
|
|
|
@ -111,16 +111,6 @@ GIB_Buffer_Insert (cbuf_t *cbuf, const char *str)
|
|||
Cbuf_Error ("parse", "Parse error in program!");
|
||||
}
|
||||
|
||||
void
|
||||
GIB_Buffer_Reset (cbuf_t *cbuf)
|
||||
{
|
||||
GIB_DATA(cbuf)->done = GIB_DATA(cbuf)->waitret = GIB_DATA(cbuf)->haveret = false;
|
||||
if (GIB_DATA(cbuf)->program)
|
||||
GIB_Tree_Free_Recursive (GIB_DATA(cbuf)->program, false);
|
||||
GIB_DATA(cbuf)->ip = 0;
|
||||
GIB_DATA(cbuf)->program = 0;
|
||||
}
|
||||
|
||||
void
|
||||
GIB_Buffer_Push_Sstack (struct cbuf_s *cbuf)
|
||||
{
|
||||
|
@ -160,5 +150,4 @@ cbuf_interpreter_t gib_interp = {
|
|||
GIB_Buffer_Insert,
|
||||
GIB_Execute,
|
||||
GIB_Execute,
|
||||
GIB_Buffer_Reset
|
||||
};
|
||||
|
|
|
@ -124,7 +124,6 @@ GIB_Return (const char *str)
|
|||
{
|
||||
dstring_t *dstr;
|
||||
if (GIB_DATA(cbuf_active)->waitret) {
|
||||
GIB_DATA(cbuf_active)->haveret = true;
|
||||
dstr = GIB_Buffer_Dsarray_Get (cbuf_active);
|
||||
dstring_clearstr (dstr);
|
||||
if (!str)
|
||||
|
@ -179,32 +178,38 @@ GIB_Function_Get_f (void)
|
|||
static void
|
||||
GIB_Local_f (void)
|
||||
{
|
||||
unsigned int i, index;
|
||||
gib_var_t *var;
|
||||
unsigned int index;
|
||||
hashtab_t *zero = 0;
|
||||
|
||||
if (GIB_Argc () < 2)
|
||||
GIB_USAGE ("var1 [var2 var3 ...]");
|
||||
else
|
||||
for (i = 1; i < GIB_Argc(); i++)
|
||||
GIB_Var_Get_Complex (&GIB_DATA(cbuf_active)->locals, &zero, GIB_Argv(i), &index, true);
|
||||
GIB_USAGE ("var [= value1 value2 ...]");
|
||||
else {
|
||||
var = GIB_Var_Get_Complex (&GIB_DATA(cbuf_active)->locals, &zero, GIB_Argv(1), &index, true);
|
||||
if (GIB_Argc() >= 3)
|
||||
GIB_Var_Assign (var, index, cbuf_active->args->argv+3, GIB_Argc() - 3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
GIB_Global_f (void)
|
||||
{
|
||||
unsigned int i, index;
|
||||
gib_var_t *var;
|
||||
unsigned int index;
|
||||
hashtab_t *zero = 0;
|
||||
|
||||
if (GIB_Argc () < 2)
|
||||
GIB_USAGE ("var1 [var2 var3 ...]");
|
||||
else
|
||||
for (i = 1; i < GIB_Argc(); i++)
|
||||
GIB_Var_Get_Complex (&GIB_DATA(cbuf_active)->globals, &zero, GIB_Argv(i), &index, true);
|
||||
GIB_USAGE ("var [= value1 value2 ...]");
|
||||
else {
|
||||
var = GIB_Var_Get_Complex (&GIB_DATA(cbuf_active)->globals, &zero, GIB_Argv(1), &index, true);
|
||||
if (GIB_Argc() >= 3)
|
||||
GIB_Var_Assign (var, index, cbuf_active->args->argv+3, GIB_Argc() - 3);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
GIB_Global_Domain_f (void)
|
||||
GIB_Domain_f (void)
|
||||
{
|
||||
if (GIB_Argc() != 2)
|
||||
GIB_USAGE ("domain");
|
||||
|
@ -218,15 +223,8 @@ GIB_Return_f (void)
|
|||
cbuf_t *sp = cbuf_active->up;
|
||||
|
||||
GIB_DATA(cbuf_active)->done = true;
|
||||
if (!GIB_Argm(0)->next) // No return values
|
||||
return;
|
||||
else if (GIB_Argc() == 1) // Empty return array
|
||||
GIB_DATA(sp)->waitret = false;
|
||||
else if (!sp || // Nothing above us on the stack
|
||||
sp->interpreter != &gib_interp || // Not a GIB buffer
|
||||
!GIB_DATA(sp)->waitret) // Doesn't want a return value
|
||||
Sys_DPrintf("GIB warning: unwanted return value(s) discarded.\n"); // Not a serious error
|
||||
else {
|
||||
|
||||
if (GIB_Argc() > 1 && sp && sp->interpreter == &gib_interp && GIB_DATA(sp)->waitret) {
|
||||
unsigned int i;
|
||||
dstring_t *dstr;
|
||||
for (i = 1; i < GIB_Argc(); i++) {
|
||||
|
@ -234,7 +232,6 @@ GIB_Return_f (void)
|
|||
dstring_clearstr (dstr);
|
||||
dstring_appendstr (dstr, GIB_Argv(i));
|
||||
}
|
||||
GIB_DATA(sp)->waitret = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -395,12 +392,36 @@ GIB_String_Equal_f (void)
|
|||
}
|
||||
|
||||
static void
|
||||
GIB_String_Findsub_f (void)
|
||||
GIB_String_Sub_f (void)
|
||||
{
|
||||
dstring_t *ret;
|
||||
int start, end, len;
|
||||
if (GIB_Argc() != 4)
|
||||
GIB_USAGE ("string start end");
|
||||
else {
|
||||
len = strlen (GIB_Argv(1));
|
||||
start = atoi (GIB_Argv(2));
|
||||
end = atoi (GIB_Argv(3));
|
||||
while (start < 0)
|
||||
start += len-1;
|
||||
while (end < 0)
|
||||
end += len;
|
||||
if (start >= len)
|
||||
return;
|
||||
if (end > len || !end)
|
||||
end = len;
|
||||
if ((ret = GIB_Return (0)))
|
||||
dstring_appendsubstr (ret, GIB_Argv(1)+start, end-start);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
GIB_String_Find_f (void)
|
||||
{
|
||||
dstring_t *ret;
|
||||
char *haystack, *res;
|
||||
if (GIB_Argc() != 3) {
|
||||
GIB_USAGE ("string substr");
|
||||
GIB_USAGE ("haystack needle");
|
||||
return;
|
||||
}
|
||||
haystack = GIB_Argv(1);
|
||||
|
@ -752,6 +773,16 @@ GIB_Print_f (void)
|
|||
Sys_Printf ("%s", GIB_Argv(1));
|
||||
}
|
||||
|
||||
static void
|
||||
GIB_Random_f (void)
|
||||
{
|
||||
dstring_t *ret;
|
||||
if (GIB_Argc() != 1)
|
||||
GIB_USAGE ("");
|
||||
else if ((ret = GIB_Return (0)))
|
||||
dsprintf (ret, "%.10g", (double) random()/(double) RAND_MAX);
|
||||
}
|
||||
|
||||
void
|
||||
GIB_Builtin_Init (qboolean sandbox)
|
||||
{
|
||||
|
@ -766,15 +797,15 @@ 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::domain", GIB_Global_Domain_f);
|
||||
GIB_Builtin_Add ("domain", GIB_Domain_f);
|
||||
GIB_Builtin_Add ("return", GIB_Return_f);
|
||||
// GIB_Builtin_Add ("dieifnot", GIB_Dieifnot_f);
|
||||
GIB_Builtin_Add ("for", GIB_For_f);
|
||||
GIB_Builtin_Add ("break", GIB_Break_f);
|
||||
GIB_Builtin_Add ("continue", GIB_Continue_f);
|
||||
GIB_Builtin_Add ("string::length", GIB_String_Length_f);
|
||||
GIB_Builtin_Add ("string::equal", GIB_String_Equal_f);
|
||||
GIB_Builtin_Add ("string::findsub", GIB_String_Findsub_f);
|
||||
GIB_Builtin_Add ("string::sub", GIB_String_Sub_f);
|
||||
GIB_Builtin_Add ("string::find", GIB_String_Find_f);
|
||||
GIB_Builtin_Add ("regex::match", GIB_Regex_Match_f);
|
||||
GIB_Builtin_Add ("regex::replace", GIB_Regex_Replace_f);
|
||||
GIB_Builtin_Add ("regex::extract", GIB_Regex_Extract_f);
|
||||
|
@ -788,4 +819,5 @@ GIB_Builtin_Init (qboolean sandbox)
|
|||
GIB_Builtin_Add ("file::delete", GIB_File_Delete_f);
|
||||
GIB_Builtin_Add ("range", GIB_Range_f);
|
||||
GIB_Builtin_Add ("print", GIB_Print_f);
|
||||
GIB_Builtin_Add ("random", GIB_Random_f);
|
||||
}
|
||||
|
|
|
@ -145,38 +145,6 @@ GIB_Execute_Prepare_Line (cbuf_t *cbuf, gib_tree_t *line)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
GIB_Execute_Assign (cbuf_t *cbuf)
|
||||
{
|
||||
cbuf_args_t *args = cbuf->args;
|
||||
gib_var_t *var;
|
||||
unsigned int index, i, len, el;
|
||||
|
||||
// First, grab our variable
|
||||
var = GIB_Var_Get_Complex (&GIB_DATA(cbuf)->locals, &GIB_DATA(cbuf)->globals, args->argv[0]->str, &index, true);
|
||||
// Now, expand the array to the correct size
|
||||
len = args->argc-2 + index;
|
||||
if (len >= var->size) {
|
||||
var->array = realloc (var->array, len * sizeof (dstring_t *));
|
||||
memset (var->array+var->size, 0, (len-var->size) * sizeof (dstring_t *));
|
||||
var->size = len;
|
||||
} else if (len < var->size) {
|
||||
for (i = len; i < var->size; i++)
|
||||
if (var->array[i])
|
||||
dstring_delete (var->array[i]);
|
||||
var->array = realloc (var->array, len * sizeof (dstring_t *));
|
||||
}
|
||||
var->size = len;
|
||||
for (i = 2; i < args->argc; i++) {
|
||||
el = i-2+index;
|
||||
if (var->array[el])
|
||||
dstring_clearstr (var->array[el]);
|
||||
else
|
||||
var->array[el] = dstring_newstr ();
|
||||
dstring_appendstr (var->array[el], args->argv[i]->str);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
GIB_Execute_For_Next (cbuf_t *cbuf)
|
||||
{
|
||||
|
@ -201,13 +169,8 @@ GIB_Execute (cbuf_t *cbuf)
|
|||
gib_builtin_t *b;
|
||||
gib_function_t *f;
|
||||
|
||||
if (g->waitret) {
|
||||
Cbuf_Error ("return", "Embedded function '%s' did not return a value.", cbuf->args->argv[0]->str);
|
||||
return;
|
||||
}
|
||||
if (!g->program) {
|
||||
if (!g->program)
|
||||
return;
|
||||
}
|
||||
if (!g->ip)
|
||||
g->ip = g->program;
|
||||
while (!g->done) {
|
||||
|
@ -225,29 +188,23 @@ GIB_Execute (cbuf_t *cbuf)
|
|||
continue;
|
||||
} else if (cbuf->args->argc) {
|
||||
if (g->ip->flags & TREE_EMBED) {
|
||||
// Get ready for return values
|
||||
g->waitret = true;
|
||||
GIB_Buffer_Push_Sstack (cbuf); // Make room for return values
|
||||
GIB_Buffer_Push_Sstack (cbuf);
|
||||
} else
|
||||
g->waitret = false;
|
||||
if (cbuf->args->argc >= 2 && !strcmp (cbuf->args->argv[1]->str, "=") && ((gib_tree_t *)cbuf->args->argm[1])->delim == ' ') {
|
||||
unsigned int index;
|
||||
GIB_Var_Assign (GIB_Var_Get_Complex (&g->locals, &g->globals, cbuf->args->argv[0]->str, &index, true), index, cbuf->args->argv+2, cbuf->args->argc-2);
|
||||
}
|
||||
if (!strcmp (cbuf->args->argv[1]->str, "=") && ((gib_tree_t *)cbuf->args->argm[1])->delim == ' ')
|
||||
GIB_Execute_Assign (cbuf);
|
||||
else if ((b = GIB_Builtin_Find (cbuf->args->argv[0]->str))) {
|
||||
b->func ();
|
||||
// If there already was an error, don't override it
|
||||
if (g->ip->flags & TREE_EMBED && !cbuf->state) {
|
||||
if (!g->haveret) {
|
||||
Cbuf_Error ("return", "Embedded builtin '%s' did not return a value.", cbuf->args->argv[0]->str);
|
||||
return;
|
||||
}
|
||||
g->haveret = g->waitret = 0;
|
||||
}
|
||||
} else if ((f = GIB_Function_Find (cbuf->args->argv[0]->str))) {
|
||||
cbuf_t *new = Cbuf_New (&gib_interp);
|
||||
cbuf->down = new;
|
||||
new->up = cbuf;
|
||||
cbuf->state = CBUF_STATE_STACK;
|
||||
GIB_Function_Execute (new, f, cbuf->args);
|
||||
if (g->ip->flags & TREE_EMBED)
|
||||
g->waitret = true;
|
||||
} else {
|
||||
GIB_Execute_Generate_Composite (cbuf);
|
||||
Cmd_Command (cbuf->args);
|
||||
|
|
|
@ -246,7 +246,7 @@ GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int flags, gib_
|
|||
// Handle comments
|
||||
} else if (program[*i] == '/' && program[*i+1] == '/') {
|
||||
for((*i) += 2; program[*i] && program[*i] != '\n'; (*i)++);
|
||||
return nodes;
|
||||
goto DONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -276,7 +276,7 @@ GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int flags, gib_
|
|||
cur->flags |= TREE_P_EMBED;
|
||||
// Add any embedded commands to top of chain
|
||||
if (new) {
|
||||
for (tmp = new; tmp->next; tmp = tmp->next); // Get to end of embedded list
|
||||
for (tmp = new; tmp->next; tmp = tmp->next);
|
||||
tmp->next = embs;
|
||||
embs = new;
|
||||
}
|
||||
|
@ -306,6 +306,7 @@ GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int flags, gib_
|
|||
(*i)++;
|
||||
node = &cur->next;
|
||||
}
|
||||
DONE:
|
||||
*embedded = embs;
|
||||
return nodes;
|
||||
ERROR:
|
||||
|
@ -375,7 +376,11 @@ GIB_Parse_Semantic_Preprocess (gib_tree_t *line)
|
|||
// If we have a while loop, handle that
|
||||
if (!strcmp (line->children->str, "while")) {
|
||||
// Sanity checks
|
||||
if (!line->children->next || !line->children->next->next || !line->children->next->next->children || line->flags & TREE_EMBED) {
|
||||
if (!line->children->next ||
|
||||
!line->children->next->next ||
|
||||
line->children->next->next->delim != '{' ||
|
||||
!line->children->next->next->children ||
|
||||
line->flags & TREE_EMBED) {
|
||||
gib_parse_error = true;
|
||||
return line;
|
||||
}
|
||||
|
@ -406,7 +411,7 @@ GIB_Parse_Semantic_Preprocess (gib_tree_t *line)
|
|||
// Find last token in line (contains program block)
|
||||
for (tmp = line->children->next->next->next->next; tmp->next; tmp = tmp->next);
|
||||
// More sanity
|
||||
if (!tmp->children) {
|
||||
if (tmp->delim != '{' || !tmp->children) {
|
||||
gib_parse_error = true;
|
||||
return line;
|
||||
}
|
||||
|
|
|
@ -127,6 +127,33 @@ GIB_Var_Get_Complex (hashtab_t **first, hashtab_t **second, char *key, unsigned
|
|||
return var;
|
||||
}
|
||||
|
||||
void
|
||||
GIB_Var_Assign (gib_var_t *var, unsigned int index, dstring_t **values, unsigned int numv)
|
||||
{
|
||||
unsigned int i, len;
|
||||
|
||||
// Now, expand the array to the correct size
|
||||
len = numv + index;
|
||||
if (len >= var->size) {
|
||||
var->array = realloc (var->array, len * sizeof (dstring_t *));
|
||||
memset (var->array+var->size, 0, (len-var->size) * sizeof (dstring_t *));
|
||||
var->size = len;
|
||||
} else if (len < var->size) {
|
||||
for (i = len; i < var->size; i++)
|
||||
if (var->array[i])
|
||||
dstring_delete (var->array[i]);
|
||||
var->array = realloc (var->array, len * sizeof (dstring_t *));
|
||||
}
|
||||
var->size = len;
|
||||
for (i = 0; i < numv; i++) {
|
||||
if (var->array[i+index])
|
||||
dstring_clearstr (var->array[i+index]);
|
||||
else
|
||||
var->array[i+index] = dstring_newstr ();
|
||||
dstring_appendstr (var->array[i+index], values[i]->str);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *
|
||||
GIB_Domain_Get_Key (void *ele, void *ptr)
|
||||
{
|
||||
|
@ -150,6 +177,7 @@ GIB_Domain_Get (const char *name)
|
|||
d = calloc (1, sizeof (gib_domain_t));
|
||||
d->name = strdup(name);
|
||||
d->vars = Hash_NewTable (1024, GIB_Var_Get_Key, GIB_Var_Free, 0);
|
||||
Hash_Add (gib_domains, d);
|
||||
}
|
||||
return d->vars;
|
||||
}
|
||||
|
|
|
@ -191,8 +191,9 @@ ERROR:
|
|||
Cbuf_DeleteStack (cbuf->down);
|
||||
cbuf->down = 0;
|
||||
}
|
||||
if (cbuf->interpreter->reset)
|
||||
cbuf->interpreter->reset (cbuf);
|
||||
// Tear it down and build it back up
|
||||
cbuf->interpreter->destruct (cbuf);
|
||||
cbuf->interpreter->construct (cbuf);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -236,5 +236,4 @@ cbuf_interpreter_t id_interp = {
|
|||
COM_insert,
|
||||
COM_execute,
|
||||
COM_execute_sets,
|
||||
NULL
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue