diff --git a/configure.ac b/configure.ac index b05cbdf5b..1d9feccb7 100644 --- a/configure.ac +++ b/configure.ac @@ -1469,7 +1469,7 @@ QF_WITH_TARGETS( QF_WITH_TARGETS( tools, [ --with-tools= compile qf tools:], - [pak,qfbsp,qfcc,qfdefs,qflight,qfmodelgen,qfprogs,qfvis,qwaq,wav],dummy + [carne,pak,qfbsp,qfcc,qfdefs,qflight,qfmodelgen,qfprogs,qfvis,qwaq,wav],dummy ) unset CL_TARGETS @@ -1631,6 +1631,7 @@ if test "x$ENABLE_servers_qw" = xyes; then QF_NEED(qw, [common net server]) fi +unset CARNE_TARGETS unset PAK_TARGETS unset QFCC_TARGETS unset QFDEFS_TARGETS @@ -1641,6 +1642,9 @@ unset QFVIS_TARGETS unset QWAQ_TARGETS unset WAV_TARGETS unset TOOLS_TARGETS +if test "x$ENABLE_tools_carne" = xyes; then + TOOLS_TARGETS="$TOOLS_TARGETS carne" +fi if test "x$ENABLE_tools_pak" = xyes; then TOOLS_TARGETS="$TOOLS_TARGETS pak" fi @@ -1671,6 +1675,8 @@ fi if test "x$ENABLE_tools_wav" = xyes; then TOOLS_TARGETS="$TOOLS_TARGETS wav" fi + +AM_CONDITIONAL(BUILD_CARNE, test "$ENABLE_tools_carne" = "yes") AM_CONDITIONAL(BUILD_PAK, test "$ENABLE_tools_pak" = "yes") AM_CONDITIONAL(BUILD_QFBSP, test "$ENABLE_tools_qfbsp" = "yes") AM_CONDITIONAL(BUILD_QFCC, test "$ENABLE_tools_qfcc" = "yes") @@ -1919,6 +1925,11 @@ QF_DEPS(QWAQ, [$(top_builddir)/libs/gamecode/engine/libQFgamecode.la $(top_builddir)/libs/util/libQFutil.la], [$(WIN32_LIBS)], ) +QF_DEPS(CARNE, + [], + [$(top_builddir)/libs/gib/libQFgib.la $(top_builddir)/libs/util/libQFutil.la], + [$(WIN32_LIBS)], +) QF_DEPS(PAK, [], [$(top_builddir)/libs/util/libQFutil.la], @@ -1996,6 +2007,7 @@ AC_OUTPUT( qw/source/Makefile tools/Makefile + tools/carne/Makefile tools/pak/Makefile tools/qfbsp/Makefile tools/qfbsp/include/Makefile diff --git a/include/QF/cbuf.h b/include/QF/cbuf.h index c9d3e3456..dec891ee3 100644 --- a/include/QF/cbuf.h +++ b/include/QF/cbuf.h @@ -59,6 +59,8 @@ typedef struct cbuf_s { CBUF_STATE_STACK, // A buffer has been added to the stack } state; + qboolean strict; // Should we tolerate unknown commands? + double resumetime; // Time when stack can be executed again void *data; // Pointer to a custom structure if needed diff --git a/include/QF/gib_function.h b/include/QF/gib_function.h index 2d762f173..b26e4a386 100644 --- a/include/QF/gib_function.h +++ b/include/QF/gib_function.h @@ -36,4 +36,5 @@ typedef struct gib_function_s { void GIB_Function_Define (const char *name, const char *program); gib_function_t *GIB_Function_Find (const char *name); +void GIB_Function_Prepare_Args (cbuf_t *cbuf, cbuf_args_t *args); void GIB_Function_Execute (cbuf_t *cbuf, gib_function_t *func, cbuf_args_t *args); diff --git a/libs/gib/gib_buffer.c b/libs/gib/gib_buffer.c index 09b3a8c54..9e232043a 100644 --- a/libs/gib/gib_buffer.c +++ b/libs/gib/gib_buffer.c @@ -50,6 +50,7 @@ GIB_Buffer_Construct (struct cbuf_s *cbuf) GIB_DATA (cbuf)->arg_composite = dstring_newstr (); GIB_DATA (cbuf)->current_token = dstring_newstr (); GIB_DATA (cbuf)->ret.retval = dstring_newstr (); + cbuf->strict = true; } void diff --git a/libs/gib/gib_builtin.c b/libs/gib/gib_builtin.c index 095652b89..56576662a 100644 --- a/libs/gib/gib_builtin.c +++ b/libs/gib/gib_builtin.c @@ -312,7 +312,7 @@ GIB_Field_Get_f (void) if (GIB_Argc() == 4) ifs = GIB_Argv (3); else if (!(ifs = GIB_Var_Get_Local (cbuf_active, "ifs"))) - ifs = " \t\n"; + ifs = " \t\n\r"; for (list = GIB_Argv(1); *list && strchr(ifs, *list); list++); while (field) { while (!strchr(ifs, *list)) @@ -389,7 +389,7 @@ GIB_For_f (void) if (GIB_Argc() == 7) ifs = GIB_Argv (5); else if (!(ifs = GIB_Var_Get_Local (cbuf_active, "ifs"))) - ifs = " \n\t"; + ifs = " \n\r\t"; dstring_append (GIB_DATA(sub)->loop_data, ifs, strlen(ifs)+1); // Store pointers to data ll = GIB_DATA(sub)->loop_data->str; diff --git a/libs/gib/gib_function.c b/libs/gib/gib_function.c index bdda5bd88..e2e81ec44 100644 --- a/libs/gib/gib_function.c +++ b/libs/gib/gib_function.c @@ -121,19 +121,26 @@ GIB_Function_Find (const char *name) return (gib_function_t *) Hash_Find (gib_functions, name); } +void +GIB_Function_Prepare_Args (cbuf_t *cbuf, cbuf_args_t *args) +{ + int i; + + for (i = 0; i < args->argc; i++) + GIB_Var_Set_Local (cbuf, va("%i", i), args->argv[i]->str); + GIB_Var_Set_Local (cbuf, "argc", va("%i", args->argc)); +} + /* GIB_Function_Execute Prepares a buffer to execute a GIB function with certain arguments */ + void GIB_Function_Execute (cbuf_t *cbuf, gib_function_t *func, cbuf_args_t *args) { - int i; - - Cbuf_AddText (cbuf, func->program->str); - for (i = 0; i < args->argc; i++) - GIB_Var_Set_Local (cbuf, va("%i", i), args->argv[i]->str); - GIB_Var_Set_Local (cbuf, "argc", va("%i", args->argc)); + Cbuf_AddText (cbuf, func->program->str); + GIB_Function_Prepare_Args (cbuf, args); } diff --git a/libs/util/cmd.c b/libs/util/cmd.c index d40d4996c..6b02ebb18 100644 --- a/libs/util/cmd.c +++ b/libs/util/cmd.c @@ -128,7 +128,9 @@ Cmd_Command (cbuf_args_t *args) if (Cvar_Command ()) return; - if (cmd_warncmd->int_val || developer->int_val) + if (cbuf_active->strict) + Cbuf_Error ("command", "Command '%s' not found.", args->argv[0]->str); + else if (cmd_warncmd->int_val || developer->int_val) Sys_Printf ("Unknown command \"%s\"\n", Cmd_Argv (0)); } diff --git a/tools/Makefile.am b/tools/Makefile.am index 7ea511953..2c570831a 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -1,2 +1,2 @@ -SUBDIRS=pak qfbsp qfcc qfdefs qflight qfmodelgen qfprogs qfvis qwaq wav +SUBDIRS=carne pak qfbsp qfcc qfdefs qflight qfmodelgen qfprogs qfvis qwaq wav bin_SCRIPTS=zpak diff --git a/tools/carne/Makefile.am b/tools/carne/Makefile.am new file mode 100644 index 000000000..bbf96147d --- /dev/null +++ b/tools/carne/Makefile.am @@ -0,0 +1,22 @@ +AUTOMAKE_OPTIONS= foreign + +CARNE_LIBS=@CARNE_LIBS@ +CARNE_DEPS=@CARNE_DEPS@ +PAK_INCS=@CARNE_INCS@ + +INCLUDES= -I$(top_srcdir)/include $(CARNE_INCS) + +if BUILD_CARNE +carne=carne +else +carne= +endif + +noinst_PROGRAMS= $(carne) +EXTRA_PROGRAMS= carne + +carne_SOURCES= main.c +carne_LDADD= $(CARNE_LIBS) +carne_DEPENDENCIES= $(CARNE_DEPS) + +EXTRA_DIST= diff --git a/tools/carne/main.c b/tools/carne/main.c new file mode 100644 index 000000000..525bb0af2 --- /dev/null +++ b/tools/carne/main.c @@ -0,0 +1,74 @@ +#include +#include +#include +#include + +#include "QF/cbuf.h" +#include "QF/cmd.h" +#include "QF/sys.h" +#include "QF/cvar.h" +#include "QF/zone.h" +#include "QF/quakefs.h" +#include "QF/quakeio.h" +#include "QF/gib_parse.h" +#include "QF/gib_init.h" +#include "QF/gib_thread.h" +#include "QF/gib_function.h" +#include "QF/dstring.h" +#include "QF/va.h" + +extern gib_thread_t *gib_threads; + +int main (int argc, char **argv) +{ + QFile *file; + char *f; + int len, i; + cbuf_args_t *args = Cbuf_ArgsNew (); + cbuf_t *mbuf = Cbuf_New (&gib_interp); + + // Initialize required QF subsystems + Cvar_Init_Hash (); + Cmd_Init_Hash (); + Cmd_Init (); + GIB_Init (); + + // Load the script + file = Qopen (argv[1], "r"); + if (file) { + len = Qfilesize (file); + f = (char *) malloc (len + 1); + if (f) { + f[len] = 0; + Qread (file, f, len); + Cbuf_InsertText (mbuf, f); + free (f); + } + Qclose (file); + } else { + printf ("Could not open %s for reading: %s\n", argv[1], strerror(errno)); + return 1; + } + + // If there is a hash-bang, strip it out + if (mbuf->buf->str[0] == '#') { + for (i = 0; mbuf->buf->str[i] != '\n' && mbuf->buf->str[i+1]; i++); + dstring_snip (mbuf->buf, 0, i+1); + } + GIB_Parse_Strip_Comments (mbuf); + + // Prepare arguments + for (i = 1; i < argc; i++) + Cbuf_ArgsAdd (args, argv[i]); + GIB_Function_Prepare_Args (mbuf, args); + Cbuf_ArgsDelete (args); + + // Main loop + while (1) { + GIB_Thread_Execute (); + Cbuf_Execute_Stack (mbuf); + // Check if there is anything left to do + if (!gib_threads && !mbuf->down && !mbuf->buf->str[0]) + return 0; + } +}