diff --git a/include/QF/gib_buffer.h b/include/QF/gib_buffer.h index c5ea85af0..88a740f56 100644 --- a/include/QF/gib_buffer.h +++ b/include/QF/gib_buffer.h @@ -40,9 +40,13 @@ typedef struct gib_buffer_data_s { // Data for handling return values struct { - qboolean waiting, available; + qboolean waiting, available; // Return value states + + // Data saved by tokenizer/processor unsigned int line_pos; // Position within line unsigned int token_pos; // Position within token + qboolean cat; // Concatenate to previous token? + char delim; // delimiter of token struct dstring_s *retval; // Returned value } ret; diff --git a/include/QF/gib_parse.h b/include/QF/gib_parse.h index 94833e8d5..26aeff1c8 100644 --- a/include/QF/gib_parse.h +++ b/include/QF/gib_parse.h @@ -28,6 +28,8 @@ */ +char GIB_Parse_Match_Angle (const char *str, unsigned int *i); + void GIB_Parse_Extract_Line (struct cbuf_s *cbuf); void GIB_Parse_Tokenize_Line (struct cbuf_s *cbuf); diff --git a/libs/util/cbuf.c b/libs/util/cbuf.c index 810a4f3f1..e1294cad4 100644 --- a/libs/util/cbuf.c +++ b/libs/util/cbuf.c @@ -146,7 +146,7 @@ Cbuf_Execute (cbuf_t *cbuf) { cbuf_active = cbuf; cbuf->state = CBUF_STATE_NORMAL; - while (cbuf->buf->str[0]) { + while (cbuf->buf->str[0] || cbuf->line->str[0]) { cbuf->interpreter->extract_line (cbuf); if (cbuf->state) break; @@ -185,6 +185,7 @@ Cbuf_Execute_Stack (cbuf_t *cbuf) sp = sp->up; } dstring_clearstr (cbuf->buf); + dstring_clearstr (cbuf->line); if (cbuf->down) { Cbuf_DeleteStack (cbuf->down); cbuf->down = 0; @@ -197,7 +198,7 @@ Cbuf_Execute_Sets (cbuf_t *cbuf) cbuf_args_t *args = cbuf->args; cbuf_active = cbuf; - while (cbuf->buf->str[0]) { + while (cbuf->buf->str[0] || cbuf->line->str[0]) { cbuf->interpreter->extract_line (cbuf); cbuf->interpreter->parse_line (cbuf); if (!args->argc) diff --git a/libs/util/gib_buffer.c b/libs/util/gib_buffer.c index 857b98c63..56ce2f6f0 100644 --- a/libs/util/gib_buffer.c +++ b/libs/util/gib_buffer.c @@ -92,13 +92,15 @@ void GIB_Buffer_Construct (struct cbuf_s *cbuf) cbuf->data = calloc (1, sizeof (gib_buffer_data_t)); GIB_DATA (cbuf)->arg_composite = dstring_newstr (); GIB_DATA (cbuf)->current_token = dstring_newstr (); + GIB_DATA (cbuf)->ret.retval = dstring_newstr (); } void GIB_Buffer_Destruct (struct cbuf_s *cbuf) { dstring_delete (GIB_DATA (cbuf)->arg_composite); dstring_delete (GIB_DATA (cbuf)->current_token); - if (GIB_DATA(cbuf)->locals) + dstring_delete (GIB_DATA (cbuf)->ret.retval); + if (GIB_DATA(cbuf)->locals && GIB_DATA(cbuf)->type == GIB_BUFFER_NORMAL) Hash_DelTable (GIB_DATA(cbuf)->locals); free (cbuf->data); } diff --git a/libs/util/gib_builtin.c b/libs/util/gib_builtin.c index 58366aaea..9a1c46f93 100644 --- a/libs/util/gib_builtin.c +++ b/libs/util/gib_builtin.c @@ -116,9 +116,31 @@ GIB_Lset_f (void) GIB_Local_Set (cbuf_active, GIB_Argv(1), GIB_Argv(2)); } +void +GIB_Return_f (void) +{ + if (GIB_Argc () > 2) + Cbuf_Error ("numargs", + "return: invalid number of arguments\n" + "usage: return "); + else { + dstring_clearstr (cbuf_active->buf); + if (GIB_Argc () == 1) + return; + if (!cbuf_active->up || !cbuf_active->up->up) + Cbuf_Error ("return","return attempted at top of stack"); + if (GIB_DATA(cbuf_active->up->up)->ret.waiting) { + dstring_clearstr (GIB_DATA(cbuf_active->up->up)->ret.retval); + dstring_appendstr (GIB_DATA(cbuf_active->up->up)->ret.retval, GIB_Argv(1)); + GIB_DATA(cbuf_active->up->up)->ret.available = true; + } + } +} + void GIB_Builtin_Init (void) { GIB_Builtin_Add ("function", GIB_Function_f); GIB_Builtin_Add ("lset", GIB_Lset_f); + GIB_Builtin_Add ("return", GIB_Return_f); } diff --git a/libs/util/gib_parse.c b/libs/util/gib_parse.c index 413a9c2f7..7058e5b13 100644 --- a/libs/util/gib_parse.c +++ b/libs/util/gib_parse.c @@ -63,7 +63,7 @@ GIB_Parse_Match_Dquote (const char *str, unsigned int *i) for ((*i)++; str[*i]; (*i)++) { if (str[*i] == '\n') return '\"'; // Newlines should never occur inside quotes, EVER - if (str[*i] == '\"') + else if (str[*i] == '\"') return 0; } return '\"'; @@ -77,12 +77,10 @@ GIB_Parse_Match_Brace (const char *str, unsigned int *i) if (str[*i] == '\"') { if ((c = GIB_Parse_Match_Dquote (str, i))) return c; - } - if (str[*i] == '{') { + } else if (str[*i] == '{') { if ((c = GIB_Parse_Match_Brace (str, i))) return c; - } - if (str[*i] == '}') + } else if (str[*i] == '}') return 0; } return '{'; @@ -96,8 +94,7 @@ GIB_Parse_Match_Paren (const char *str, unsigned int *i) if (str[*i] == '(') { if ((c = GIB_Parse_Match_Paren (str, i))) return c; - } - if (str[*i] == ')') + } else if (str[*i] == ')') return 0; } return '('; @@ -264,9 +261,9 @@ GIB_Parse_Tokenize_Line (struct cbuf_s *cbuf) dstring_t *arg = GIB_DATA(cbuf)->current_token; const char *str = cbuf->line->str; cbuf_args_t *args = cbuf->args; - static qboolean cat = false; + qboolean cat = false; char delim; - int i = 0; + int i; // This function can be interrupted to call a GIB // subroutine. First we need to clean up anything @@ -275,19 +272,15 @@ GIB_Parse_Tokenize_Line (struct cbuf_s *cbuf) // Do we have a left-over token that needs processing? if (GIB_DATA(cbuf)->ret.waiting) { - // FIXME: Call processing function here - if (GIB_DATA(cbuf)->ret.waiting) // Still not done? - return; - i = GIB_DATA(cbuf)->ret.line_pos; // Start where we left off + if (GIB_Process_Token (arg, GIB_DATA(cbuf)->ret.delim)) + return; // Still not done, or error + GIB_Parse_Add_Token (cbuf->args, GIB_DATA(cbuf)->ret.cat, arg); + i = GIB_DATA(cbuf)->ret.line_pos; // Start tokenizing where we left off } else { args->argc = 0; // Start from scratch i = 0; - cat = false; } - - // Get just the first token so we can look up any - // parsing options that a builtin requests - + while (str[i]) { while (isspace(str[i])) // Eliminate whitespace i++; @@ -298,15 +291,14 @@ GIB_Parse_Tokenize_Line (struct cbuf_s *cbuf) i++; continue; } + dstring_clearstr (arg); delim = GIB_Parse_Get_Token (str, &i, arg); if (!delim) break; Sys_DPrintf("Got token: %s\n", arg->str); - // FIXME: Command sub goes here with subroutine handling - if (GIB_Process_Token (arg, delim)) - goto FILTER_ERROR; + goto FILTER_ERROR; // Error or GIB subroutine needs to be called GIB_Parse_Add_Token (cbuf->args, cat, arg); if (cat) @@ -314,13 +306,14 @@ GIB_Parse_Tokenize_Line (struct cbuf_s *cbuf) if (delim != ' ') // Move into whitespace if we haven't already i++; - dstring_clearstr (arg); } GIB_Parse_Generate_Composite (cbuf); + dstring_clearstr (cbuf->line); return; -FILTER_ERROR: // Error during filtering, clean up mess - dstring_clearstr (arg); - args->argc = 0; +FILTER_ERROR: + GIB_DATA(cbuf)->ret.line_pos = i; // save our information in case + GIB_DATA(cbuf)->ret.cat = cat; // error is not fatal + GIB_DATA(cbuf)->ret.delim = delim; return; } diff --git a/libs/util/gib_process.c b/libs/util/gib_process.c index f2d948985..6eb74842a 100644 --- a/libs/util/gib_process.c +++ b/libs/util/gib_process.c @@ -35,6 +35,7 @@ #include "QF/cbuf.h" #include "QF/cvar.h" #include "QF/gib_buffer.h" +#include "QF/gib_parse.h" #include "exp.h" @@ -95,12 +96,63 @@ GIB_Process_Math (struct dstring_s *token) return 0; } +int +GIB_Process_Embedded (struct dstring_s *token) +{ + cbuf_t *sub; + int i, n; + char c; + + if (GIB_DATA(cbuf_active)->ret.waiting) { + if (!GIB_DATA(cbuf_active)->ret.available) { + GIB_DATA(cbuf_active)->ret.waiting = false; + Cbuf_Error ("return", "Embedded command did not return a value."); + return -1; + } + i = GIB_DATA(cbuf_active)->ret.token_pos; // Jump to the right place + } else + i = 0; + + for (; token->str[i]; i++) { + if (token->str[i] == '<') { + n = i; + if ((c = GIB_Parse_Match_Angle (token->str, &i))) { + Cbuf_Error ("parse", "Could not find matching %c", c); + return -1; + } + if (GIB_DATA(cbuf_active)->ret.available) { + dstring_replace (token, n, i-n+1, GIB_DATA(cbuf_active)->ret.retval->str, + strlen(GIB_DATA(cbuf_active)->ret.retval->str)); + i = n + strlen(GIB_DATA(cbuf_active)->ret.retval->str) - 1; + GIB_DATA(cbuf_active)->ret.waiting = false; + GIB_DATA(cbuf_active)->ret.available = false; + } else { + sub = Cbuf_New (&gib_interp); + GIB_DATA(sub)->type = GIB_BUFFER_PROXY; + GIB_DATA(sub)->locals = GIB_DATA(cbuf_active)->locals; + dstring_insert (sub->buf, 0, token->str+n+1, i-n-1); + if (cbuf_active->down) + Cbuf_DeleteStack (cbuf_active->down); + cbuf_active->down = sub; + sub->up = cbuf_active; + cbuf_active->state = CBUF_STATE_STACK; + GIB_DATA(cbuf_active)->ret.waiting = true; + GIB_DATA(cbuf_active)->ret.token_pos = n; + return -1; + } + } + } + return 0; +} + int GIB_Process_Token (struct dstring_s *token, char delim) { - if (delim != '{' && delim != '\"') + if (delim != '{' && delim != '\"') { + if (GIB_Process_Embedded (token)) + return -1; GIB_Process_Variables_All (token); - + } if (delim == '(') if (GIB_Process_Math (token)) return -1; diff --git a/libs/util/idparse.c b/libs/util/idparse.c index 2d5b25df0..05bbbb4f6 100644 --- a/libs/util/idparse.c +++ b/libs/util/idparse.c @@ -153,7 +153,8 @@ COM_extract_line (cbuf_t *cbuf) void COM_parse_line (cbuf_t *cbuf) { - COM_TokenizeString (cbuf->line->str, cbuf->args);; + COM_TokenizeString (cbuf->line->str, cbuf->args); + dstring_clearstr (cbuf->line); } void