diff --git a/include/QF/Makefile.am b/include/QF/Makefile.am index 4ef52bffc..3e6fd34d0 100644 --- a/include/QF/Makefile.am +++ b/include/QF/Makefile.am @@ -3,9 +3,10 @@ SUBDIRS = GL plugin includedir = $(prefix)/include/QF include_HEADERS = bspfile.h cbuf.h cdaudio.h checksum.h clip_hull.h cmd.h \ console.h crc.h csqc.h cvar.h dstring.h draw.h gcc_attr.h gib_buffer.h \ - gib_parse.h gib_process.h hash.h hl.h idparse.h in_event.h info.h \ - input.h joystick.h keys.h link.h locs.h mathlib.h mdfour.h model.h \ - modelgen.h msg.h pak.h pakfile.h pcx.h plugin.h pr_comp.h pr_debug.h \ - pr_obj.h progs.h qargs.h qdefs.h qendian.h qfplist.h qtypes.h render.h \ - screen.h sizebuf.h skin.h sound.h spritegn.h sys.h teamplay.h texture.h \ - tga.h uint32.h va.h ver_check.h vfile.h vfs.h vid.h wad.h zone.h + gib_builtin.h gib_function.h gib_parse.h gib_process.h hash.h hl.h idparse.h \ + in_event.h info.h input.h joystick.h keys.h link.h locs.h mathlib.h \ + mdfour.h model.h modelgen.h msg.h pak.h pakfile.h pcx.h plugin.h \ + pr_comp.h pr_debug.h pr_obj.h progs.h qargs.h qdefs.h qendian.h \ + qfplist.h qtypes.h render.h screen.h sizebuf.h skin.h sound.h \ + spritegn.h sys.h teamplay.h texture.h tga.h uint32.h va.h ver_check.h \ + vfile.h vfs.h vid.h wad.h zone.h diff --git a/include/QF/cbuf.h b/include/QF/cbuf.h index e846ce210..f64eec2fb 100644 --- a/include/QF/cbuf.h +++ b/include/QF/cbuf.h @@ -43,13 +43,12 @@ typedef struct cbuf_args_s { int argv_size; } cbuf_args_t; + typedef struct cbuf_s { struct dstring_s *buf; struct dstring_s *line; cbuf_args_t *args; - void (*extract_line) (struct cbuf_s *cbuf); - void (*parse_line) (struct cbuf_s *cbuf); - void (*destructor) (struct cbuf_s *cbuf); + struct cbuf_interpreter_s *interpreter; struct cbuf_s *up, *down; // The stack @@ -63,23 +62,28 @@ typedef struct cbuf_s { void *data; // Pointer to a custom structure if needed } cbuf_t; +typedef struct cbuf_interpreter_s { + void (*extract_line) (struct cbuf_s *cbuf); + void (*parse_line) (struct cbuf_s *cbuf); + void (*execute_line) (struct cbuf_s *cbuf); + void (*construct) (struct cbuf_s *cbuf); + void (*destruct) (struct cbuf_s *cbuf); +} cbuf_interpreter_t; + extern cbuf_t *cbuf_active; cbuf_args_t *Cbuf_ArgsNew (void); void Cbuf_ArgsDelete (cbuf_args_t *); void Cbuf_ArgsAdd (cbuf_args_t *args, const char *arg); -cbuf_t * Cbuf_New ( - void (*extract) (struct cbuf_s *cbuf), - void (*parse) (struct cbuf_s *cbuf), - void (*construct) (struct cbuf_s *cbuf), - void (*destruct) (struct cbuf_s *cbuf) - ); +cbuf_t * Cbuf_New (cbuf_interpreter_t *interp); void Cbuf_Delete (cbuf_t *cbuf); +void Cbuf_DeleteStack (cbuf_t *stack); void Cbuf_AddText (cbuf_t *cbuf, const char *text); void Cbuf_InsertText (cbuf_t *cbuf, const char *text); void Cbuf_Execute (cbuf_t *cbuf); +void Cbuf_Execute_Stack (cbuf_t *cbuf); void Cbuf_Execute_Sets (cbuf_t *cbuf); void Cbuf_Error (const char *class, const char *fmt, ...); diff --git a/include/QF/dstring.h b/include/QF/dstring.h index 2d0c3ff82..e249c55c9 100644 --- a/include/QF/dstring.h +++ b/include/QF/dstring.h @@ -44,19 +44,19 @@ dstring_t *dstring_new(void); void dstring_delete (dstring_t *dstr); void dstring_adjust (dstring_t *dstr); void dstring_append (dstring_t *dstr, const char *data, unsigned int len); -void dstring_insert(dstring_t *dstr, const char *data, unsigned int len, - unsigned int pos); +void dstring_insert (dstring_t *dstr, unsigned int pos, const char *data, + unsigned int len); void dstring_snip (dstring_t *dstr, unsigned int pos, unsigned int len); void dstring_clear (dstring_t *dstr); -void dstring_replace (dstring_t *dstr, const char *data, unsigned int len, - unsigned int pos, unsigned int rlen); - +void dstring_replace (dstring_t *dstr, unsigned int pos, unsigned int rlen, + const char *data, unsigned int len); + // String-specific functions dstring_t *dstring_newstr (void); void dstring_appendstr (dstring_t *dstr, const char *str); void dstring_appendsubstr (dstring_t *dstr, const char *str, unsigned int len); -void dstring_insertstr (dstring_t *dstr, const char *str, unsigned int pos); -void dstring_insertsubstr (dstring_t *dstr, const char *str, unsigned int pos, +void dstring_insertstr (dstring_t *dstr, unsigned int pos, const char *str); +void dstring_insertsubstr (dstring_t *dstr, unsigned int pos, const char *str, unsigned int len); void dstring_clearstr (dstring_t *dstr); diff --git a/include/QF/gib_buffer.h b/include/QF/gib_buffer.h index 0b56068d6..55e216f4c 100644 --- a/include/QF/gib_buffer.h +++ b/include/QF/gib_buffer.h @@ -32,6 +32,21 @@ typedef struct gib_buffer_data_s { struct dstring_s *arg_composite; + struct dstring_s *current_token; + + // Data for handling return values + struct { + qboolean waiting, available; + unsigned int line_pos; // Position within line + unsigned int token_pos; // Position within token + struct dstring_s *retval; // Returned value + } ret; + + enum { + GIB_BUFFER_NORMAL, // Normal buffer + GIB_BUFFER_LOOP, // Looping buffer + GIB_BUFFER_PROXY // Responsible for embedded command + } type; } gib_buffer_data_t; void GIB_Buffer_Construct (struct cbuf_s *cbuf); diff --git a/include/QF/gib_builtin.h b/include/QF/gib_builtin.h new file mode 100644 index 000000000..e7c6132b4 --- /dev/null +++ b/include/QF/gib_builtin.h @@ -0,0 +1,38 @@ +/* + #FILENAME# + + #DESCRIPTION# + + Copyright (C) 2002 #AUTHOR# + + Author: #AUTHOR# + Date: #DATE# + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +typedef struct gib_builtin_s { + struct dstring_s *name; + void (*func) (void); +} gib_builtin_t; + +void GIB_Builtin_Add (const char *name, void (*func) (void)); +gib_builtin_t *GIB_Builtin_Find (const char *name); +void GIB_Builtin_Init (void); diff --git a/include/QF/gib_function.h b/include/QF/gib_function.h new file mode 100644 index 000000000..fdbf1face --- /dev/null +++ b/include/QF/gib_function.h @@ -0,0 +1,36 @@ +/* + #FILENAME# + + #DESCRIPTION# + + Copyright (C) 2002 #AUTHOR# + + Author: #AUTHOR# + Date: #DATE# + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +typedef struct gib_function_s { + struct dstring_s *name, *program; +} gib_function_t; + +void GIB_Function_Define (const char *name, const char *program); +gib_function_t *GIB_Function_Find (const char *name); diff --git a/include/QF/gib_parse.h b/include/QF/gib_parse.h index 05cb26099..94833e8d5 100644 --- a/include/QF/gib_parse.h +++ b/include/QF/gib_parse.h @@ -30,3 +30,5 @@ void GIB_Parse_Extract_Line (struct cbuf_s *cbuf); void GIB_Parse_Tokenize_Line (struct cbuf_s *cbuf); + +extern struct cbuf_interpreter_s gib_interp; diff --git a/include/QF/gib_process.h b/include/QF/gib_process.h index f8b96437d..e32b23f9a 100644 --- a/include/QF/gib_process.h +++ b/include/QF/gib_process.h @@ -29,3 +29,5 @@ */ void GIB_Process_Variable (struct dstring_s *token); +void GIB_Process_Variables_All (struct dstring_s *token); +int GIB_Process_Math (struct dstring_s *token); diff --git a/include/QF/idparse.h b/include/QF/idparse.h index 9409e6747..6a595cbd2 100644 --- a/include/QF/idparse.h +++ b/include/QF/idparse.h @@ -32,5 +32,5 @@ extern const char *com_token; const char *COM_Parse (const char *data); void COM_TokenizeString (const char *str, cbuf_args_t *args); -void COM_extract_line (cbuf_t *cbuf); -void COM_parse_line (cbuf_t *cbuf); + +extern struct cbuf_interpreter_s id_interp; diff --git a/libs/gamecode/builtins/bi_cbuf.c b/libs/gamecode/builtins/bi_cbuf.c index c9ae80d4a..d5e97d044 100644 --- a/libs/gamecode/builtins/bi_cbuf.c +++ b/libs/gamecode/builtins/bi_cbuf.c @@ -40,7 +40,7 @@ static inline void check_cbuf (void) { if (!cbuf) - cbuf = Cbuf_New (COM_extract_line, COM_parse_line, NULL, NULL); + cbuf = Cbuf_New (&id_interp); } static void diff --git a/libs/gamecode/builtins/bi_keys.c b/libs/gamecode/builtins/bi_keys.c index 4b84630ef..8cbc45d34 100644 --- a/libs/gamecode/builtins/bi_keys.c +++ b/libs/gamecode/builtins/bi_keys.c @@ -50,7 +50,7 @@ static inline void check_cbuf (void) { if (!cbuf) - cbuf = Cbuf_New (COM_extract_line, COM_parse_line, NULL, NULL); + cbuf = Cbuf_New (&id_interp); } /* diff --git a/libs/util/Makefile.am b/libs/util/Makefile.am index dc273f007..7a309cd29 100644 --- a/libs/util/Makefile.am +++ b/libs/util/Makefile.am @@ -27,9 +27,9 @@ libQFutil_la_LIBADD= libasm.la $(Z_LIBS) $(DL_LIBS) libQFutil_la_DEPENDENCIES= libasm.la libQFutil_la_SOURCES= \ buildnum.c cbuf.c checksum.c cmd.c crc.c cvar.c dstring.c exp.c fendian.c \ - getopt.c getopt1.c gib_buffer.c gib_parse.c gib_process.c hash.c idparse.c \ - info.c link.c mathlib.c mdfour.c msg.c ops.c pakfile.c pcx.c plugin.c qargs.c \ - qendian.c qfplist.c quakefs.c quakeio.c sizebuf.c string.c sys.c tga.c va.c \ - ver_check.c wad.c zone.c $(fnmatch) + getopt.c getopt1.c gib_buffer.c gib_builtin.c gib_function.c gib_parse.c \ + gib_process.c hash.c idparse.c info.c link.c mathlib.c mdfour.c msg.c ops.c \ + pakfile.c pcx.c plugin.c qargs.c qendian.c qfplist.c quakefs.c quakeio.c \ + sizebuf.c string.c sys.c tga.c va.c ver_check.c wad.c zone.c $(fnmatch) EXTRA_DIST= $(asm_src) $(fnmatch_src) diff --git a/libs/util/cbuf.c b/libs/util/cbuf.c index 2331bdb6a..810a4f3f1 100644 --- a/libs/util/cbuf.c +++ b/libs/util/cbuf.c @@ -91,23 +91,16 @@ Cbuf_ArgsAdd (cbuf_args_t *args, const char *arg) } cbuf_t * -Cbuf_New ( - void (*extract) (struct cbuf_s *cbuf), - void (*parse) (struct cbuf_s *cbuf), - void (*construct) (struct cbuf_s *cbuf), - void (*destruct) (struct cbuf_s *cbuf) - ) +Cbuf_New (cbuf_interpreter_t *interp) { cbuf_t *cbuf = calloc (1, sizeof (cbuf_t)); cbuf->buf = dstring_newstr (); cbuf->line = dstring_newstr (); cbuf->args = Cbuf_ArgsNew (); - cbuf->extract_line = extract; - cbuf->parse_line = parse; - cbuf->destructor = destruct; - if (construct) - construct (cbuf); + cbuf->interpreter = interp; + if (interp->construct) + interp->construct (cbuf); return cbuf; } @@ -119,11 +112,22 @@ Cbuf_Delete (cbuf_t *cbuf) dstring_delete (cbuf->buf); dstring_delete (cbuf->line); Cbuf_ArgsDelete (cbuf->args); - if (cbuf->destructor) - cbuf->destructor (cbuf); + if (cbuf->interpreter->destruct) + cbuf->interpreter->destruct (cbuf); free (cbuf); } +void +Cbuf_DeleteStack (cbuf_t *stack) +{ + cbuf_t *next; + + for (; stack; stack = next) { + next = stack->down; + Cbuf_Delete (stack); + } +} + void Cbuf_AddText (cbuf_t *cbuf, const char *text) { @@ -133,27 +137,25 @@ Cbuf_AddText (cbuf_t *cbuf, const char *text) void Cbuf_InsertText (cbuf_t *cbuf, const char *text) { - dstring_insertstr (cbuf->buf, "\n", 0); - dstring_insertstr (cbuf->buf, text, 0); + dstring_insertstr (cbuf->buf, 0, "\n"); + dstring_insertstr (cbuf->buf, 0, text); } void Cbuf_Execute (cbuf_t *cbuf) { - cbuf_args_t *args = cbuf->args; - cbuf_active = cbuf; cbuf->state = CBUF_STATE_NORMAL; while (cbuf->buf->str[0]) { - cbuf->extract_line (cbuf); + cbuf->interpreter->extract_line (cbuf); if (cbuf->state) break; - cbuf->parse_line (cbuf); + cbuf->interpreter->parse_line (cbuf); if (cbuf->state) // Merging extract and parse break; // will get rid of extra checks - if (!args->argc) + if (!cbuf->args->argc) continue; - Cmd_Command (args); + cbuf->interpreter->execute_line (cbuf); if (cbuf->state) break; } @@ -166,6 +168,10 @@ Cbuf_Execute_Stack (cbuf_t *cbuf) for (sp = cbuf; sp->down; sp = sp->down); while (sp) { + if (sp->down) { + Cbuf_Delete (sp->down); + sp->down = 0; + } Cbuf_Execute (sp); if (sp->state) { if (sp->state == CBUF_STATE_STACK) { @@ -175,13 +181,13 @@ Cbuf_Execute_Stack (cbuf_t *cbuf) break; else return; - } + } sp = sp->up; } dstring_clearstr (cbuf->buf); - for (cbuf = cbuf->down; cbuf; cbuf = sp) { // Reduce, reuse, recycle - sp = cbuf->down; - Cbuf_Delete (cbuf); + if (cbuf->down) { + Cbuf_DeleteStack (cbuf->down); + cbuf->down = 0; } } @@ -192,8 +198,8 @@ Cbuf_Execute_Sets (cbuf_t *cbuf) cbuf_active = cbuf; while (cbuf->buf->str[0]) { - cbuf->extract_line (cbuf); - cbuf->parse_line (cbuf); + cbuf->interpreter->extract_line (cbuf); + cbuf->interpreter->parse_line (cbuf); if (!args->argc) continue; if (strequal (args->argv[0]->str, "set") diff --git a/libs/util/cmd.c b/libs/util/cmd.c index 5f40c4372..d4e5e266b 100644 --- a/libs/util/cmd.c +++ b/libs/util/cmd.c @@ -52,6 +52,7 @@ static const char rcsid[] = #include "QF/sys.h" #include "QF/vfs.h" #include "QF/zone.h" +#include "QF/gib_builtin.h" typedef struct cmdalias_s { struct cmdalias_s *next; @@ -589,7 +590,11 @@ Cmd_Init (void) Cmd_AddCommand ("wait", Cmd_Wait_f, "Wait a game tic"); cmd_warncmd = Cvar_Get ("cmd_warncmd", "0", CVAR_NONE, NULL, "Toggles the " "display of error messages for unknown commands"); - cmd_cbuf = Cbuf_New (COM_extract_line, COM_parse_line, NULL, NULL); + cmd_cbuf = Cbuf_New (&id_interp); + + // FIXME: GIB should really be initialized elsewhere + + GIB_Builtin_Init (); } int diff --git a/libs/util/dstring.c b/libs/util/dstring.c index 04c9d055e..7e16f55c2 100644 --- a/libs/util/dstring.c +++ b/libs/util/dstring.c @@ -77,8 +77,8 @@ dstring_append (dstring_t *dstr, const char *data, unsigned int len) } void -dstring_insert (dstring_t *dstr, const char *data, unsigned int len, - unsigned int pos) +dstring_insert (dstring_t *dstr, unsigned int pos, const char *data, + unsigned int len) { unsigned int oldsize = dstr->size; @@ -104,8 +104,8 @@ dstring_clear (dstring_t *dstr) } void -dstring_replace (dstring_t *dstr, const char *data, unsigned int len, - unsigned int pos, unsigned int rlen) +dstring_replace (dstring_t *dstr, unsigned int pos, unsigned int rlen, + const char *data, unsigned int len) { unsigned int oldsize = dstr->size; if (rlen < len) { @@ -158,21 +158,21 @@ dstring_appendsubstr (dstring_t *dstr, const char *str, unsigned int len) } void -dstring_insertstr (dstring_t *dstr, const char *str, unsigned int pos) +dstring_insertstr (dstring_t *dstr, unsigned int pos, const char *str) { // Don't insert strlen + 1 to achieve concatenation - dstring_insert (dstr, str, strlen (str), pos); + dstring_insert (dstr, pos, str, strlen (str)); } void -dstring_insertsubstr (dstring_t *dstr, const char *str, unsigned int pos, +dstring_insertsubstr (dstring_t *dstr, unsigned int pos, const char *str, unsigned int len) { unsigned int l = strlen (str); if (len > l) len = l; - dstring_insert (dstr, str, len, pos); + dstring_insert (dstr, pos, str, len); } void diff --git a/libs/util/gib_buffer.c b/libs/util/gib_buffer.c index ce06dfa6e..4b11db44d 100644 --- a/libs/util/gib_buffer.c +++ b/libs/util/gib_buffer.c @@ -38,6 +38,7 @@ 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 (); } void GIB_Buffer_Destruct (struct cbuf_s *cbuf) diff --git a/libs/util/gib_builtin.c b/libs/util/gib_builtin.c new file mode 100644 index 000000000..43b71ae64 --- /dev/null +++ b/libs/util/gib_builtin.c @@ -0,0 +1,111 @@ +/* + #FILENAME# + + #DESCRIPTION# + + Copyright (C) 2002 #AUTHOR# + + Author: #AUTHOR# + Date: #DATE# + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#include + +#include "QF/sys.h" +#include "QF/cmd.h" +#include "QF/cbuf.h" +#include "QF/hash.h" +#include "QF/dstring.h" +#include "QF/gib_builtin.h" +#include "QF/gib_function.h" + +hashtab_t *gib_builtins; + +const char * +GIB_Builtin_Get_Key (void *ele, void *ptr) +{ + return ((gib_builtin_t *)ele)->name->str; +} + +void +GIB_Builtin_Free (void *ele, void *ptr) +{ + gib_builtin_t *b; + b = (gib_builtin_t *) ele; + dstring_delete (b->name); + free (b); +} + +void +GIB_Builtin_Add (const char *name, void (*func) (void)) +{ + gib_builtin_t *new; + + if (!gib_builtins) + gib_builtins = Hash_NewTable (1024, GIB_Builtin_Get_Key, GIB_Builtin_Free, 0); + + new = calloc (1, sizeof (gib_builtin_t)); + new->func = func; + new->name = dstring_newstr(); + dstring_appendstr (new->name, name); + Hash_Add (gib_builtins, new); +} + +gib_builtin_t * +GIB_Builtin_Find (const char *name) +{ + if (!gib_builtins) + return 0; + return (gib_builtin_t *) Hash_Find (gib_builtins, name); +} + +unsigned int +GIB_Argc (void) +{ + return cbuf_active->args->argc; +} + +const char * +GIB_Argv (unsigned int arg) +{ + if (arg < cbuf_active->args->argc) + return cbuf_active->args->argv[arg]->str; + else + return ""; +} + +void +GIB_Function_f (void) +{ + if (GIB_Argc () != 3) { + Cbuf_Error ("numargs", + "function: invalid number of arguments\n" + "usage: function function_name {program}"); + } else + GIB_Function_Define (GIB_Argv(1), GIB_Argv(2)); +} + +void +GIB_Builtin_Init (void) +{ + GIB_Builtin_Add ("function", GIB_Function_f); +} diff --git a/libs/util/gib_function.c b/libs/util/gib_function.c new file mode 100644 index 000000000..0a21e0a89 --- /dev/null +++ b/libs/util/gib_function.c @@ -0,0 +1,87 @@ +/* + #FILENAME# + + #DESCRIPTION# + + Copyright (C) 2002 #AUTHOR# + + Author: #AUTHOR# + Date: #DATE# + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#include + +#include "QF/dstring.h" +#include "QF/hash.h" +#include "QF/gib_function.h" + +hashtab_t *gib_functions = 0; + +gib_function_t * +GIB_Function_New (void) +{ + gib_function_t *new = calloc (1, sizeof (gib_function_t)); + new->name = dstring_newstr(); + new->program = dstring_newstr(); + + return new; +} + +const char * +GIB_Function_Get_Key (void *ele, void *ptr) +{ + return ((gib_function_t *)ele)->name->str; +} + +void +GIB_Function_Free (void *ele, void *ptr) +{ + gib_function_t *func = (gib_function_t *)ele; + dstring_delete (func->name); + dstring_delete (func->program); +} + +void +GIB_Function_Define (const char *name, const char *program) +{ + gib_function_t *func; + + if (!gib_functions) + gib_functions = Hash_NewTable (1024, GIB_Function_Get_Key, GIB_Function_Free, 0); + func = Hash_Find(gib_functions, name); + if (func) + dstring_clearstr (func->program); + else { + func = GIB_Function_New (); + dstring_appendstr (func->name, name); + Hash_Add (gib_functions, func); + } + dstring_appendstr (func->program, program); +} + +gib_function_t * +GIB_Function_Find (const char *name) +{ + if (!gib_functions) + return 0; + return (gib_function_t *) Hash_Find (gib_functions, name); +} diff --git a/libs/util/gib_parse.c b/libs/util/gib_parse.c index 4307542cf..1a644083e 100644 --- a/libs/util/gib_parse.c +++ b/libs/util/gib_parse.c @@ -33,9 +33,27 @@ #include "QF/sys.h" #include "QF/dstring.h" +#include "QF/cmd.h" #include "QF/cbuf.h" #include "QF/gib_buffer.h" #include "QF/gib_process.h" +#include "QF/gib_builtin.h" +#include "QF/gib_function.h" + +// Interpreter structure and prototypes + +void GIB_Parse_Extract_Line (cbuf_t *cbuf); +void GIB_Parse_Tokenize_Line (cbuf_t *cbuf); +void GIB_Parse_Execute_Line (cbuf_t *cbuf); + +cbuf_interpreter_t gib_interp = { + GIB_Parse_Extract_Line, + GIB_Parse_Tokenize_Line, + GIB_Parse_Execute_Line, + GIB_Buffer_Construct, + GIB_Buffer_Destruct, +}; + /* Co-recursive parsing functions */ @@ -43,6 +61,8 @@ inline char 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 if (str[*i] == '\"') return 0; } @@ -68,34 +88,66 @@ GIB_Parse_Match_Brace (const char *str, unsigned int *i) return '{'; } +inline char +GIB_Parse_Match_Paren (const char *str, unsigned int *i) +{ + char c; + for ((*i)++; str[*i]; (*i)++) { + if (str[*i] == '(') { + if ((c = GIB_Parse_Match_Paren (str, i))) + return c; + } + if (str[*i] == ')') + return 0; + } + return '('; +} + void GIB_Parse_Extract_Line (struct cbuf_s *cbuf) { int i; char c; + + if (GIB_DATA(cbuf)->ret.waiting) // Not ready for next line + return; + dstring_t *dstr = cbuf->buf; dstring_clearstr (cbuf->line); - + for (i = 0; dstr->str[i]; i++) { if (dstr->str[i] == '{') { if ((c = GIB_Parse_Match_Brace (dstr->str, &i))) { - Cbuf_Error ("parse", "Could not find match for character %c", c); + Cbuf_Error ("parse", "Could not find matching %c", c); return; } - } - else if (dstr->str[i] == '\n' || dstr->str[i] == ';') + } else if (dstr->str[i] == '\"') { + if ((c = GIB_Parse_Match_Dquote (dstr->str, &i))) { + Cbuf_Error ("parse", "Could not find matching %c", c); + return; + } + } else if (dstr->str[i] == '\n' || dstr->str[i] == ';') break; + else if (dstr->str[i] == '/' && dstr->str[i+1] == '/') { + char *n; + if ((n = strchr (dstr->str+i, '\n'))) + dstring_snip (dstr, i, n-dstr->str); + else { + dstring_snip (dstr, i, strlen(dstr->str+i)); + i--; // So we don't go past null + } + } } - if (i) { - dstring_insert (cbuf->line, dstr->str, i, 0); - Sys_DPrintf ("extracted line: %s\n", cbuf->line->str); - if (dstr->str[0]) - dstring_snip (dstr, 0, i); + if (dstr->str[0]) { + if (i) { + dstring_insert (cbuf->line, 0, dstr->str, i); + Sys_DPrintf ("extracted line: %s\n", cbuf->line->str); + } + dstring_snip (dstr, 0, i + (dstr->str[i] == '\n' || dstr->str[i] == ';')); } - else - dstring_clearstr (dstr); + return; } @@ -109,24 +161,32 @@ GIB_Parse_Get_Token (const char *str, unsigned int *i, dstring_t *dstr) n = *i; // Save start position if (str[*i] == '\"') { if ((c = GIB_Parse_Match_Dquote (str, i))) { - Cbuf_Error ("parse", "Could not find match for character %c", c); + Cbuf_Error ("parse", "Could not find matching %c", c); return 0; // Parse error } else { - dstring_insert (dstr, str+n+1, *i-n-1, 0); + dstring_insert (dstr, 0, str+n+1, *i-n-1); return '\"'; } } else if (str[*i] == '{') { if ((c = GIB_Parse_Match_Brace (str, i))) { - Cbuf_Error ("parse", "Could not find match for character %c", c); + Cbuf_Error ("parse", "Could not find matching %c", c); return 0; // Parse error } else { - dstring_insert (dstr, str+n+1, *i-n-1, 0); + dstring_insert (dstr, 0, str+n+1, *i-n-1); return '{'; } + } else if (str[*i] == '(') { + if ((c = GIB_Parse_Match_Paren (str, i))) { + Cbuf_Error ("parse", "Could not find matching %c", c); + return 0; // Parse error + } else { + dstring_insert (dstr, 0, str+n+1, *i-n-1); + return '\('; + } } else { while (str[*i] && !isspace(str[*i]) && str[*i] != ',') // find end of token (*i)++; - dstring_insert (dstr, str+n, *i-n, 0); + dstring_insert (dstr, 0, str+n, *i-n); return ' '; } return 0; // We should never get here @@ -140,28 +200,59 @@ GIB_Parse_Generate_Composite (struct cbuf_s *cbuf) dstring_clearstr (GIB_DATA (cbuf)->arg_composite); for (i = 0; i < args->argc; i++) { + // ->str could be moved by realloc when a dstring is resized + // so save the offset instead of the pointer args->args[i] = (const char *) strlen (GIB_DATA (cbuf)->arg_composite->str); dstring_appendstr (GIB_DATA (cbuf)->arg_composite, args->argv[i]->str); dstring_appendstr (GIB_DATA (cbuf)->arg_composite, " "); } + + // Get rid of trailing space GIB_DATA (cbuf)->arg_composite->str[strlen(GIB_DATA (cbuf)->arg_composite->str)-1] = 0; + for (i = 0; i < args->argc; i++) + // now that arg_composite is done we can add the pointer to the stored + // offsets and get valid pointers. This *should* be portable. args->args[i] += (unsigned long int) GIB_DATA (cbuf)->arg_composite->str; } +inline void +GIB_Parse_Add_Token (struct cbuf_args_s *args, qboolean cat, dstring_t *token) +{ + if (cat) { + dstring_appendstr (args->argv[args->argc-1], token->str); + } else + Cbuf_ArgsAdd (args, token->str); +} + void GIB_Parse_Tokenize_Line (struct cbuf_s *cbuf) { - dstring_t *arg = dstring_newstr (); + dstring_t *arg = GIB_DATA(cbuf)->current_token; const char *str = cbuf->line->str; cbuf_args_t *args = cbuf->args; - qboolean cat = false; + static qboolean cat = false; char delim; int i; - cbuf->args->argc = 0; + // This function can be interrupted to call a GIB + // subroutine. First we need to clean up anything + // we left unfinished - for (i = 0;str[i];) { + // 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 + } else { + args->argc = 0; // Start from scratch + i = 0; + cat = false; + } + + for (i = 0; str[i];) { while (isspace(str[i])) // Eliminate whitespace i++; if (!str[i]) // Blank token @@ -175,17 +266,51 @@ GIB_Parse_Tokenize_Line (struct cbuf_s *cbuf) if (!delim) break; Sys_DPrintf("Got token: %s\n", arg->str); - if (*arg->str == '$' && delim == ' ') - GIB_Process_Variable (arg); - if (cat) { - dstring_appendstr (args->argv[args->argc-1], arg->str); + + // Global filters -- command sub and var sub + + // FIXME: Command sub goes here with subroutine handling + + if (delim != '{' && delim != '\"') + GIB_Process_Variables_All (arg); + + if (delim == '(') + if (GIB_Process_Math (arg)) + goto FILTER_ERROR; // GOTO??!?!?!? AHHHH! + + // Add token to list + GIB_Parse_Add_Token (args, cat, arg); + if (cat) cat = false; - } else - Cbuf_ArgsAdd (args, arg->str); - if (delim != ' ') + + if (delim != ' ') // Move into whitespace if we haven't already i++; dstring_clearstr (arg); } - dstring_delete (arg); GIB_Parse_Generate_Composite (cbuf); + return; +FILTER_ERROR: // Error during filtering, clean up mess + dstring_clearstr (arg); + args->argc = 0; + return; } + +void GIB_Parse_Execute_Line (cbuf_t *cbuf) +{ + gib_builtin_t *b; + gib_function_t *f; + + if ((b = GIB_Builtin_Find (cbuf->args->argv[0]->str))) + b->func (); + else if ((f = GIB_Function_Find (cbuf->args->argv[0]->str))) { + cbuf_t *sub = Cbuf_New (&gib_interp); + Cbuf_AddText (sub, f->program->str); + if (cbuf_active->down) + Cbuf_DeleteStack (cbuf_active->down); + cbuf_active->down = sub; + sub->up = cbuf_active; + cbuf_active->state = CBUF_STATE_STACK; + } else + Cmd_Command (cbuf->args); +} + diff --git a/libs/util/gib_process.c b/libs/util/gib_process.c index ca98559de..da7554206 100644 --- a/libs/util/gib_process.c +++ b/libs/util/gib_process.c @@ -28,22 +28,64 @@ */ -#include -#include +#include +#include + +#include "QF/dstring.h" +#include "QF/cbuf.h" +#include "QF/cvar.h" + +#include "exp.h" void -GIB_Process_Variable (struct dstring_s *token) +GIB_Process_Variable (struct dstring_s *dstr) { int i; cvar_t *var; - for (i = 0; token->str[i] == '$'; i++); + for (i = 0; dstr->str[i] == '$'; i++); i--; for (; i >= 0; i--) { - var = Cvar_FindVar (token->str+i+1); + var = Cvar_FindVar (dstr->str+i+1); if (!var) return; - token->str[i] = 0; - dstring_appendstr (token, var->string); + dstr->str[i] = 0; + dstring_appendstr (dstr, var->string); } } + +void +GIB_Process_Variables_All (struct dstring_s *token) +{ + int i, n; + dstring_t *var = dstring_newstr (); + + for (i = 0; token->str[i]; i++) { + if (token->str[i] == '$') { + for (n = 1; token->str[i+n] == '$'; n++); // get past $s + for (; isalnum(token->str[i+n]); n++); // find end of var + dstring_insert (var, 0, token->str+i, n); // extract it + GIB_Process_Variable (var); + dstring_replace (token, i, n, var->str, strlen(var->str)); + i += strlen (var->str) - 1; + dstring_clearstr (var); + } + } +} + +int +GIB_Process_Math (struct dstring_s *token) +{ + double value; + + value = EXP_Evaluate (token->str); + if (EXP_ERROR) { + // FIXME: Give real error descriptions + Cbuf_Error ("math", "Expression \"%s\" caused error %i", token->str, EXP_ERROR); + return -1; + } else { + dstring_clearstr (token); + dsprintf (token, "%.10g", value); + } + return 0; +} diff --git a/libs/util/idparse.c b/libs/util/idparse.c index 4e3119eba..2d5b25df0 100644 --- a/libs/util/idparse.c +++ b/libs/util/idparse.c @@ -32,6 +32,7 @@ #include "QF/dstring.h" #include "QF/cbuf.h" +#include "QF/cmd.h" static dstring_t *_com_token; const char *com_token; @@ -68,7 +69,7 @@ skipwhite: while (1) { c = data[i++]; if (c == '"' || !c) { - dstring_insert (_com_token, data, i - 1, 0); + dstring_insert (_com_token, 0, data, i - 1); goto done; } } @@ -77,7 +78,7 @@ skipwhite: do { i++; } while (data[i] && !isspace ((byte) data[i])); - dstring_insert (_com_token, data, i, 0); + dstring_insert (_com_token, 0, data, i); done: com_token = _com_token->str; return data + i; @@ -140,7 +141,7 @@ COM_extract_line (cbuf_t *cbuf) break; } if (i) - dstring_insert (cbuf->line, text, i, 0); + dstring_insert (cbuf->line, 0, text, i); if (text[i]) { dstring_snip (cbuf->buf, 0, i + 1); } else { @@ -154,3 +155,17 @@ COM_parse_line (cbuf_t *cbuf) { COM_TokenizeString (cbuf->line->str, cbuf->args);; } + +void +COM_execute_line (cbuf_t *cbuf) +{ + Cmd_Command (cbuf->args); +} + +cbuf_interpreter_t id_interp = { + COM_extract_line, + COM_parse_line, + COM_execute_line, + NULL, + NULL, +}; diff --git a/nq/source/host.c b/nq/source/host.c index efb1874d0..d42b51a47 100644 --- a/nq/source/host.c +++ b/nq/source/host.c @@ -851,7 +851,7 @@ Host_Init (void) { Con_Printf ("Host_Init\n"); - host_cbuf = Cbuf_New (COM_extract_line, COM_parse_line, NULL, NULL); + host_cbuf = Cbuf_New (&id_interp); cmd_source = src_command; Cvar_Init_Hash (); diff --git a/qw/source/cl_main.c b/qw/source/cl_main.c index 48b5e2952..4e4f9443c 100644 --- a/qw/source/cl_main.c +++ b/qw/source/cl_main.c @@ -1663,7 +1663,7 @@ CL_Init_Memory (void) void Host_Init (void) { - cl_cbuf = Cbuf_New (COM_extract_line, COM_parse_line, NULL, NULL); + cl_cbuf = Cbuf_New (&id_interp); Cvar_Init_Hash (); Cmd_Init_Hash (); diff --git a/qw/source/sv_main.c b/qw/source/sv_main.c index 3915e0333..e014c6ac6 100644 --- a/qw/source/sv_main.c +++ b/qw/source/sv_main.c @@ -263,7 +263,7 @@ SV_Error (const char *error, va_list argptr) inerror = true; dvsprintf (string, error, argptr); - dstring_insertstr (string, "server crashed: ", 0); + dstring_insertstr (string, 0, "server crashed: "); dstring_appendstr (string, "\n"); SV_FinalMessage (string->str); @@ -1915,7 +1915,7 @@ SV_Frame (float time) SV_GetConsoleCommands (); // process console commands - Cbuf_Execute (sv_cbuf); + Cbuf_Execute_Stack (sv_cbuf); SV_CheckVars (); @@ -2408,8 +2408,7 @@ SV_Init (void) // COM_AddParm ("-game"); // COM_AddParm ("qw"); - sv_cbuf = Cbuf_New (GIB_Parse_Extract_Line, GIB_Parse_Tokenize_Line, - GIB_Buffer_Construct, GIB_Buffer_Destruct); + sv_cbuf = Cbuf_New (&gib_interp); sv_args = Cbuf_ArgsNew (); Sys_RegisterShutdown (SV_Shutdown);