diff --git a/include/QF/cbuf.h b/include/QF/cbuf.h index e9bd4e039..cd802240e 100644 --- a/include/QF/cbuf.h +++ b/include/QF/cbuf.h @@ -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; diff --git a/include/QF/gib_buffer.h b/include/QF/gib_buffer.h index 4abf42c17..4fd1856e9 100644 --- a/include/QF/gib_buffer.h +++ b/include/QF/gib_buffer.h @@ -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); diff --git a/include/QF/gib_vars.h b/include/QF/gib_vars.h index 59c9efb08..526155d51 100644 --- a/include/QF/gib_vars.h +++ b/include/QF/gib_vars.h @@ -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); diff --git a/libs/gib/gib_buffer.c b/libs/gib/gib_buffer.c index a2927ba00..d6de592e8 100644 --- a/libs/gib/gib_buffer.c +++ b/libs/gib/gib_buffer.c @@ -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 }; diff --git a/libs/gib/gib_builtin.c b/libs/gib/gib_builtin.c index ca3f54e0a..a268b2f5c 100644 --- a/libs/gib/gib_builtin.c +++ b/libs/gib/gib_builtin.c @@ -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); } diff --git a/libs/gib/gib_execute.c b/libs/gib/gib_execute.c index 387dc2f1a..d377978a3 100644 --- a/libs/gib/gib_execute.c +++ b/libs/gib/gib_execute.c @@ -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); diff --git a/libs/gib/gib_parse.c b/libs/gib/gib_parse.c index 926bab845..606335024 100644 --- a/libs/gib/gib_parse.c +++ b/libs/gib/gib_parse.c @@ -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; } diff --git a/libs/gib/gib_vars.c b/libs/gib/gib_vars.c index ef61e9258..0eda2ba02 100644 --- a/libs/gib/gib_vars.c +++ b/libs/gib/gib_vars.c @@ -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; } diff --git a/libs/util/cbuf.c b/libs/util/cbuf.c index f812d5b08..c539df151 100644 --- a/libs/util/cbuf.c +++ b/libs/util/cbuf.c @@ -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 diff --git a/libs/util/idparse.c b/libs/util/idparse.c index 0e7033217..e16892e0d 100644 --- a/libs/util/idparse.c +++ b/libs/util/idparse.c @@ -236,5 +236,4 @@ cbuf_interpreter_t id_interp = { COM_insert, COM_execute, COM_execute_sets, - NULL };