diff --git a/include/Makefile.am b/include/Makefile.am index 3411a7d96..30a7c6ee9 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -4,8 +4,8 @@ SUBDIRS = QF EXTRA_DIST = asm_i386.h alsa_funcs_list.h adivtab.h anorm_dots.h anorms.h \ asm_draw.h block16.h block8.h buildnum.h compat.h context_sdl.h \ context_x11.h d_iface.h d_ifacea.h d_local.h dga_check.h exp.h fbset.h \ - getopt.h gib_buffer.h gib_builtin.h gib_execute.h gib_function.h \ - gib_handle.h gib_parse.h gib_process.h gib_regex.h gib_semantics.h \ + getopt.h gib_buffer.h gib_builtin.h gib_classes.h gib_execute.h gib_function.h \ + gib_handle.h gib_object.h gib_parse.h gib_process.h gib_regex.h gib_semantics.h \ gib_thread.h gib_tree.h gib_vars.h gl_warp_sin.h in_win.h logos.h menu.h \ net_dgrm.h net_loop.h net_udp.h net_vcr.h net_wins.h netchan.h netmain.h \ old_keys.h ops.h qstring.h quakeasm.h regex.h r_cvar.h r_dynamic.h \ diff --git a/include/QF/cbuf.h b/include/QF/cbuf.h index 6b7144c73..3755c2f29 100644 --- a/include/QF/cbuf.h +++ b/include/QF/cbuf.h @@ -54,6 +54,7 @@ typedef struct cbuf_s { enum { CBUF_STATE_NORMAL = 0, // Normal condition CBUF_STATE_WAIT, // Buffer is stalled until next frame + CBUF_STATE_BLOCKED, // Buffer is blocked until further notice CBUF_STATE_ERROR, // An unrecoverable error occured CBUF_STATE_STACK, // A buffer has been added to the stack CBUF_STATE_JUNK // Buffer can be freed or reused diff --git a/include/QF/gib.h b/include/QF/gib.h index 5ea38d8e8..0474889b3 100644 --- a/include/QF/gib.h +++ b/include/QF/gib.h @@ -36,6 +36,96 @@ #include "QF/dstring.h" #include "QF/cbuf.h" +#include "QF/hash.h" +#include "QF/llist.h" + +// Object interface + +typedef void (*gib_reply_handler) (int argc, const char **argv, void *data); + +typedef struct gib_signal_s { + const char *name; + struct gib_object_s *receiver; + struct gib_slot_s *slot; +} gib_signal_t; + +typedef struct gib_slot_s { + const char *mesg; + struct gib_object_s *sender; + struct gib_signal_s *signal; +} gib_slot_t; + +typedef struct gib_object_s { + struct gib_class_s *class; + hashtab_t *methods; + void **data; + unsigned long int handle, refs; + hashtab_t *signals; + llist_t *slots; +} gib_object_t; + +typedef struct gib_message_s { + int argc; + const char **argv; + gib_reply_handler reply; + void *replydata; +} gib_message_t; + +typedef struct gib_method_s { + const char *name; + int (*func) (struct gib_object_s *obj, struct gib_method_s *method, void *data, gib_message_t message); + struct gib_method_s *parent; + struct gib_class_s *class; + void *data; +} gib_method_t; + +typedef int (*gib_message_handler) (gib_object_t *obj, gib_method_t *method, void *data, gib_message_t message); +typedef void * (*gib_obj_constructor) (gib_object_t *obj); +typedef void (*gib_obj_destructor) (void *data); + +typedef struct gib_class_s { + const char *name; + hashtab_t *methods, *class_methods; + gib_obj_constructor construct, class_construct; + gib_obj_destructor destruct; + unsigned int depth; + struct gib_object_s *classobj; + struct gib_class_s *parent; +} gib_class_t; + +typedef struct gib_methodtab_s { + const char *name; + gib_message_handler func; + void *data; +} gib_methodtab_t; + +typedef struct gib_classdesc_s { + const char *name; + const char *parentname; + gib_obj_constructor construct, class_construct; + gib_obj_destructor destruct; + struct gib_methodtab_s *methods, *class_methods; +} gib_classdesc_t; + +#define GIB_Reply(mesg,argc,argv) if ((mesg).reply) ((mesg).reply(argc,argv,(mesg).replydata)) +#define GIB_ForwardToSuper(mesg,obj,method) ((method)->parent->func ((obj), (method)->parent, (obj)->data[(method)->parent->class->depth], (mesg))) + +void GIB_Class_Create (gib_classdesc_t *desc); +gib_object_t *GIB_Object_Create (const char *classname, qboolean classobj); +void GIB_Object_Destroy (gib_object_t *obj); +void GIB_Object_Incref (gib_object_t *obj); +void GIB_Object_Decref (gib_object_t *obj); +int GIB_Send (gib_object_t *obj, int argc, const char **argv, gib_reply_handler reply, void *replydata); +int GIB_SendToMethod (gib_object_t *obj, gib_method_t *method, int argc, const + char **argv, gib_reply_handler reply, void *replydata); +gib_object_t *GIB_Object_Get (const char *id); +void GIB_Object_Signal_Slot_Pair (gib_object_t *sender, const char *signal, + gib_object_t *receiver, const char *slot); +void GIB_Object_Signal_Slot_Destroy (gib_object_t *sender, const char *signal, + gib_object_t *receiver, const char *slot); +void GIB_Object_Signal_Emit (gib_object_t *sender, int argc, const char + **argv); +void GIB_Object_Init (void); // Buffer access (required to use GIB_Arg* macros) @@ -58,8 +148,15 @@ typedef struct gib_buffer_data_s { } *values; unsigned int size, p; } stack; + struct { + struct gib_object_s *obj; + struct gib_method_s *method; + struct gib_message_s mesg; + } reply; struct hashtab_s *locals; // Local variables struct hashtab_s *globals; // Current domain + void (*dnotify) (cbuf_t *cbuf, void *data); + void *ddata; } gib_buffer_data_t; // Builtin function interface @@ -99,6 +196,7 @@ cbuf_interpreter_t *GIB_Interpreter (void); // Thread interface void GIB_Thread_Execute (void); +unsigned int GIB_Thread_Count (void); // Init interface @@ -106,9 +204,8 @@ void GIB_Init (qboolean sandbox); // Handle interface -unsigned long int GIB_Handle_New (void *data, unsigned short int class); -void GIB_Handle_Free (unsigned long int num, unsigned short int class); -void *GIB_Handle_Get (unsigned long int num, unsigned short int class); -unsigned short int GIB_Handle_Class_New (void); +unsigned long int GIB_Handle_New (gib_object_t *data); +void GIB_Handle_Free (unsigned long int num); +gib_object_t *GIB_Handle_Get (unsigned long int num); #endif diff --git a/include/QF/llist.h b/include/QF/llist.h index b65ad5e11..ae4e0b124 100644 --- a/include/QF/llist.h +++ b/include/QF/llist.h @@ -58,8 +58,9 @@ llist_node_t *llist_getnode (llist_t *list, void *element); llist_node_t *llist_insertafter (llist_node_t *ref, void *element); llist_node_t *llist_insertbefore (llist_node_t *ref, void *element); void *llist_remove (llist_node_t *ref); +unsigned int llist_size (llist_t *llist); void llist_iterate (llist_t *list, llist_iterator_t iterate); void *llist_find (llist_t *list, void *comparison); llist_node_t *llist_findnode (llist_t *list, void *comparison); - +void *llist_createarray (llist_t *list, size_t esize); #endif diff --git a/include/gib_buffer.h b/include/gib_buffer.h index 6b0b1384e..c6503e2b7 100644 --- a/include/gib_buffer.h +++ b/include/gib_buffer.h @@ -40,6 +40,7 @@ void GIB_Buffer_Set_Program (cbuf_t *cbuf, gib_tree_t *program); void GIB_Buffer_Push_Sstack (struct cbuf_s *cbuf); void GIB_Buffer_Pop_Sstack (struct cbuf_s *cbuf); dstring_t *GIB_Buffer_Dsarray_Get (struct cbuf_s *cbuf); +void GIB_Buffer_Reply_Callback (int argc, const char **argv, void *data); void GIB_Buffer_Error (cbuf_t *cbuf, const char *type, const char *fmt, va_list args); extern struct cbuf_interpreter_s gib_interp; diff --git a/include/gib_classes.h b/include/gib_classes.h new file mode 100644 index 000000000..8dd777bd5 --- /dev/null +++ b/include/gib_classes.h @@ -0,0 +1,38 @@ +/* + gib_classes.h + + Built-in GIB classes + + Copyright (C) 2003 Brian Koropoff + + 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 + + $Id$ +*/ + +#ifndef _GIB_CLASSES_H +#define _GIB_CLASSES_H + +#include "gib_tree.h" + +void GIB_Classes_Build_Scripted (const char *name, const char *parentname, + gib_tree_t *tree, gib_script_t *script); +void GIB_Classes_Init (void); + +#endif diff --git a/include/gib_function.h b/include/gib_function.h index d3535b92e..d90857271 100644 --- a/include/gib_function.h +++ b/include/gib_function.h @@ -46,7 +46,7 @@ typedef struct gib_function_s { qboolean exported; } gib_function_t; -void GIB_Function_Define (const char *name, const char *text, gib_tree_t *program, gib_script_t *script, hashtab_t *globals); +gib_function_t *GIB_Function_Define (const char *name, const char *text, gib_tree_t *program, gib_script_t *script, hashtab_t *globals); gib_function_t *GIB_Function_Find (const char *name); void GIB_Function_Prepare_Args (cbuf_t *cbuf, const char **args, unsigned int argc); void GIB_Function_Prepare_Args_D (cbuf_t *cbuf, dstring_t **args, unsigned int argc); diff --git a/include/gib_handle.h b/include/gib_handle.h index 04a5430b5..10670bbd9 100644 --- a/include/gib_handle.h +++ b/include/gib_handle.h @@ -26,6 +26,7 @@ 59 Temple Place - Suite 330 Boston, MA 02111-1307, USA + $Id$ */ @@ -33,9 +34,8 @@ #define __gib_handle_h typedef struct gib_handle_s { - unsigned short int class; unsigned long int num; - void *data; + gib_object_t *data; struct gib_handle_s *next; } gib_handle_t; diff --git a/include/gib_object.h b/include/gib_object.h new file mode 100644 index 000000000..b31a5de3a --- /dev/null +++ b/include/gib_object.h @@ -0,0 +1,36 @@ +/* + gib_object.h + + GIB object handling functions + + Copyright (C) 2003 Brian Koropoff + + 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 + + $Id$ +*/ + +#ifndef _GIB_OBJECT_H +#define _GIB_OBJECT_H + +#define CLASSDATA(class,type) ((type *) ((class)->classobj->data[(class)->depth])) + +void GIB_Object_Init (void); + +#endif diff --git a/include/gib_thread.h b/include/gib_thread.h index f8ef6014c..cd2aabb82 100644 --- a/include/gib_thread.h +++ b/include/gib_thread.h @@ -33,23 +33,13 @@ #define __gib_thread_h #include "gib_function.h" +#include "QF/cbuf.h" -typedef struct gib_thread_s { - unsigned long int id; - struct cbuf_s *cbuf; - struct gib_thread_s *prev, *next; -} gib_thread_t; - -void GIB_Thread_Add (gib_thread_t *thread); -void GIB_Thread_Remove (gib_thread_t *thread); -void GIB_Thread_Delete (gib_thread_t *thread); -gib_thread_t *GIB_Thread_New (void); +cbuf_t *GIB_Thread_New (void); +void GIB_Thread_Delete (cbuf_t *thread); void GIB_Thread_Init (void); int GIB_Event_Register (const char *name, gib_function_t *func); void GIB_Event_Init (void); -extern gib_thread_t *gib_thread_first, *gib_thread_last; -extern unsigned short int gib_thread_class; - #endif diff --git a/include/gib_tree.h b/include/gib_tree.h index 904fd03fb..f67c58a91 100644 --- a/include/gib_tree.h +++ b/include/gib_tree.h @@ -53,11 +53,12 @@ typedef struct gib_tree_s { TREE_T_CMD, // A command TREE_T_COND, // Conditional jump TREE_T_ASSIGN, // Assignment + TREE_T_SEND, // Message sending TREE_T_JUMP, // Jump TREE_T_ARG, // Argument (not a line) TREE_T_FORNEXT, // Fetch next arg in for loop TREE_T_META, // Info node - TREE_T_NOP // Do nothing (label, etc) + TREE_T_LABEL // Label (or no-op) } type; struct gib_tree_s *children, *next, *jump; } gib_tree_t; diff --git a/include/gib_vars.h b/include/gib_vars.h index bd197fa5b..bb7751728 100644 --- a/include/gib_vars.h +++ b/include/gib_vars.h @@ -53,5 +53,6 @@ gib_var_t *GIB_Var_Get_Complex (hashtab_t **first, hashtab_t **second, char *key gib_var_t *GIB_Var_Get_Very_Complex (hashtab_t ** first, hashtab_t ** second, dstring_t *key, unsigned int start, unsigned int *ind, qboolean create); void GIB_Var_Assign (gib_var_t *var, unsigned int index, dstring_t **values, unsigned int numv, qboolean shrink); hashtab_t *GIB_Domain_Get (const char *name); +hashtab_t *GIB_Var_Hash_New (void); void GIB_Var_Init (void); diff --git a/libs/gamecode/builtins/bi_gib.c b/libs/gamecode/builtins/bi_gib.c index e725f0310..4edbee459 100644 --- a/libs/gamecode/builtins/bi_gib.c +++ b/libs/gamecode/builtins/bi_gib.c @@ -146,39 +146,32 @@ bi_GIB_Return (progs_t *pr) R_INT (pr) = GIB_CanReturn () ? 1 : 0; } -static void -bi_GIB_Handle_Class_New (progs_t *pr) -{ - R_INT (pr) = GIB_Handle_Class_New (); -} - static void bi_GIB_Handle_New (progs_t *pr) { - long *qcptr = malloc (sizeof (long)); - *qcptr = P_POINTER (pr, 0); - R_INT (pr) = GIB_Handle_New (qcptr, P_INT (pr, 1)); + //long *qcptr = malloc (sizeof (long)); + //*qcptr = P_POINTER (pr, 0); + //R_INT (pr) = GIB_Handle_New (qcptr); } static void bi_GIB_Handle_Free (progs_t *pr) { - unsigned long int hand = P_INT (pr, 0); - unsigned short int cl = (unsigned short) P_INT (pr, 1); - long *qcptr = GIB_Handle_Get (hand, cl); + //unsigned long int hand = P_INT (pr, 0); + //long *qcptr = GIB_Handle_Get (hand); - free (qcptr); - GIB_Handle_Free (hand, cl); + //free (qcptr); + //GIB_Handle_Free (hand); } static void bi_GIB_Handle_Get (progs_t *pr) { - long *hand = GIB_Handle_Get (P_INT (pr, 0), (unsigned short) P_INT (pr, 1)); - if (hand) - R_INT (pr) = *hand; - else - R_INT (pr) = 0; + //long *hand = GIB_Handle_Get (P_INT (pr, 0)); + //if (hand) + // R_INT (pr) = *hand; + //else + // R_INT (pr) = 0; } void @@ -193,7 +186,6 @@ GIB_Progs_Init (progs_t *pr) PR_AddBuiltin (pr, "GIB_Builtin_Add", bi_GIB_Builtin_Add, -1); PR_AddBuiltin (pr, "GIB_Return", bi_GIB_Return, -1); - PR_AddBuiltin (pr, "GIB_Handle_Class_New", bi_GIB_Handle_Class_New, -1); PR_AddBuiltin (pr, "GIB_Handle_New", bi_GIB_Handle_New, -1); PR_AddBuiltin (pr, "GIB_Handle_Free", bi_GIB_Handle_Free, -1); PR_AddBuiltin (pr, "GIB_Handle_Get", bi_GIB_Handle_Get, -1); diff --git a/libs/gib/Makefile.am b/libs/gib/Makefile.am index d5f94068f..597bdc08b 100644 --- a/libs/gib/Makefile.am +++ b/libs/gib/Makefile.am @@ -6,6 +6,6 @@ lib_LTLIBRARIES= libQFgib.la libQFgib_la_LDFLAGS= -version-info 1:0:0 libQFgib_la_SOURCES= \ - gib_buffer.c gib_builtin.c gib_execute.c gib_function.c gib_parse.c gib_handle.c \ - gib_process.c gib_regex.c gib_thread.c gib_vars.c gib_init.c gib_tree.c \ + gib_buffer.c gib_builtin.c gib_classes.c gib_execute.c gib_function.c gib_parse.c gib_handle.c \ + gib_object.c gib_process.c gib_regex.c gib_thread.c gib_vars.c gib_init.c gib_tree.c \ gib_semantics.c ops.c exp.c regex.c diff --git a/libs/gib/gib_buffer.c b/libs/gib/gib_buffer.c index 9967c1c8c..4260b57b1 100644 --- a/libs/gib/gib_buffer.c +++ b/libs/gib/gib_buffer.c @@ -67,6 +67,9 @@ GIB_Buffer_Destruct (struct cbuf_s *cbuf) gib_buffer_data_t *g = GIB_DATA (cbuf); unsigned int i, j; + if (g->dnotify) + g->dnotify (cbuf, g->ddata); + dstring_delete (g->arg_composite); if (g->locals) Hash_DelTable (g->locals); @@ -107,7 +110,7 @@ GIB_Buffer_Reset (struct cbuf_s *cbuf) g->program = g->ip = 0; g->stack.p = 0; g->waitret = false; - + g->reply.obj = NULL; } void @@ -265,6 +268,18 @@ GIB_Buffer_Get_Line_Info (cbuf_t * cbuf, char **line) } } +void +GIB_Buffer_Reply_Callback (int argc, const char **argv, void *data) +{ + cbuf_t *cbuf = (cbuf_t *) data; + int i; + + for (i = 0; i < argc; i++) + dstring_copystr (GIB_Buffer_Dsarray_Get (cbuf), argv[i]); + if (cbuf->state == CBUF_STATE_BLOCKED) + cbuf->state = CBUF_STATE_NORMAL; +} + void GIB_Buffer_Error (cbuf_t * cbuf, const char *type, const char *fmt, va_list args) diff --git a/libs/gib/gib_builtin.c b/libs/gib/gib_builtin.c index e0cfe180a..0c6fa2dc1 100644 --- a/libs/gib/gib_builtin.c +++ b/libs/gib/gib_builtin.c @@ -64,6 +64,7 @@ const char rcsid[] = #include "gib_thread.h" #include "gib_handle.h" #include "gib_builtin.h" +#include "gib_classes.h" char gib_null_string[] = ""; @@ -235,7 +236,7 @@ GIB_Local_f (void) static void -GIB_Global_f (void) +GIB_Shared_f (void) { gib_var_t *var; unsigned int index; @@ -312,7 +313,19 @@ GIB_Return_f (void) GIB_DATA (cbuf_active)->ip = &fakeip; - if (GIB_Argc () > 1 && sp && sp->interpreter == &gib_interp + if (GIB_DATA (cbuf_active)->reply.obj) { + gib_buffer_data_t *g = GIB_DATA (cbuf_active); + const char **argv = malloc (sizeof (char *) * GIB_Argc() -1); + int i; + + for (i = 1; i < GIB_Argc(); i++) + argv[i-1] = GIB_Argv(i); + + GIB_Reply (g->reply.mesg, GIB_Argc()-1, argv); + free (argv); + g->dnotify = NULL; + GIB_Object_Decref (g->reply.obj); + } else if (GIB_Argc () > 1 && sp && sp->interpreter == &gib_interp && GIB_DATA (sp)->waitret) { int i; dstring_t *dstr; @@ -714,68 +727,6 @@ GIB_Text_From_Decimal_f (void) } } -static void -GIB_Thread_Create_f (void) -{ - gib_function_t *f; - - if (GIB_Argc () < 2) - GIB_USAGE ("function [arg1 arg2 ...]"); - else if (!(f = GIB_Function_Find (GIB_Argv (1)))) - GIB_Error ("function", "%s: no function named '%s' exists.", - GIB_Argv (0), GIB_Argv (1)); - else { - gib_thread_t *thread = GIB_Thread_New (); - - GIB_Function_Execute_D (thread->cbuf, f, cbuf_active->args->argv + 1, - cbuf_active->args->argc - 1); - GIB_Thread_Add (thread); - if (GIB_CanReturn ()) - dsprintf (GIB_Return (0), "%lu", thread->id); - } -} - -static void -GIB_Thread_Kill_f (void) -{ - if (GIB_Argc () != 2) - GIB_USAGE ("id"); - else { - gib_thread_t *thread; - cbuf_t *cur; - unsigned long int id = strtoul (GIB_Argv (1), 0, 10); - - thread = GIB_Handle_Get (id, gib_thread_class); - if (!thread) { - GIB_Error ("thread", "%s: thread %lu does not exist.", GIB_Argv (0), id); - return; - } - - // If we are currently running this thread, set an error state so we exit it cleanly - // if it were simply nuked, a crash would result - for (cur = thread->cbuf; cur->down && cur->down->state != CBUF_STATE_JUNK; cur = cur->down) - if (cur == cbuf_active) { - cur->state = CBUF_STATE_ERROR; - return; - } - GIB_Thread_Remove (thread); - GIB_Thread_Delete (thread); - } -} - -static void -GIB_Thread_List_f (void) -{ - if (GIB_Argc () != 1) - GIB_USAGE (""); - else if (GIB_CanReturn ()) { - gib_thread_t *cur; - - for (cur = gib_thread_first; cur; cur = cur->next) - dsprintf (GIB_Return (0), "%lu", cur->id); - } -} - static void GIB_Event_Register_f (void) { @@ -998,6 +949,42 @@ GIB_Print_f (void) Sys_Printf ("%s", GIB_Argv (1)); } +static void +GIB_Class_f (void) +{ + if (GIB_Argc () == 5) + GIB_Classes_Build_Scripted (GIB_Argv(1), GIB_Argv(3), + GIB_Argm (4)->children, + GIB_DATA(cbuf_active)->script); + else + GIB_Classes_Build_Scripted (GIB_Argv(1), NULL, + GIB_Argm (2)->children, + GIB_DATA(cbuf_active)->script); +} + +static void +GIB_Emit_f (void) +{ + if (GIB_Argc () < 2) { + GIB_USAGE ("signal [arg1 arg2 ...]"); + return; + } else if (!GIB_DATA(cbuf_active)->reply.obj) { + GIB_Error ("emit", "Cannot emit signal in this context."); + return; + } else { + int i; + const char **argv = malloc (GIB_Argc () - 1); + + for (i = 1; i < GIB_Argc (); i ++) + argv[i-1] = GIB_Argv (1); + + GIB_Object_Signal_Emit (GIB_DATA(cbuf_active)->reply.obj, + GIB_Argc () - 1, argv); + + free (argv); + } +} + static void GIB_bp1_f (void) { @@ -1031,7 +1018,8 @@ GIB_Builtin_Init (qboolean sandbox) GIB_Builtin_Add ("function::get", GIB_Function_Get_f); 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 ("shared", GIB_Shared_f); + GIB_Builtin_Add ("global", GIB_Shared_f); GIB_Builtin_Add ("delete", GIB_Delete_f); GIB_Builtin_Add ("domain", GIB_Domain_f); GIB_Builtin_Add ("domain::clear", GIB_Domain_Clear_f); @@ -1052,9 +1040,6 @@ GIB_Builtin_Init (qboolean sandbox) GIB_Builtin_Add ("text::toBrown", GIB_Text_Brown_f); GIB_Builtin_Add ("text::toDecimal", GIB_Text_To_Decimal_f); GIB_Builtin_Add ("text::fromDecimal", GIB_Text_From_Decimal_f); - GIB_Builtin_Add ("thread::create", GIB_Thread_Create_f); - GIB_Builtin_Add ("thread::kill", GIB_Thread_Kill_f); - GIB_Builtin_Add ("thread::getList", GIB_Thread_List_f); GIB_Builtin_Add ("event::register", GIB_Event_Register_f); GIB_Builtin_Add ("file::read", GIB_File_Read_f); GIB_Builtin_Add ("file::write", GIB_File_Write_f); @@ -1063,6 +1048,8 @@ 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 ("class", GIB_Class_f); + GIB_Builtin_Add ("emit", GIB_Emit_f); GIB_Builtin_Add ("bp1", GIB_bp1_f); GIB_Builtin_Add ("bp2", GIB_bp2_f); GIB_Builtin_Add ("bp3", GIB_bp3_f); diff --git a/libs/gib/gib_classes.c b/libs/gib/gib_classes.c new file mode 100644 index 000000000..3a6ba4682 --- /dev/null +++ b/libs/gib/gib_classes.c @@ -0,0 +1,461 @@ +/* + gib_classes.c + + GIB built-in classes + + Copyright (C) 2003 Brian Koropoff + + 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 + +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include + +#include "QF/gib.h" +#include "QF/va.h" +#include "QF/sys.h" +#include "QF/llist.h" +#include "gib_object.h" +#include "gib_thread.h" +#include "gib_classes.h" +#include "gib_tree.h" +#include "gib_vars.h" + +/* + Begin Object class + + The root of the GIB class hierarchy. Responsible for retain/release + reference counting, creating instances of an object, returning + an object handle, and reporting object type. +*/ + +typedef struct baseobj_s { + llist_t *receivers, *subscribed; +} baseobj_t; + +static int +Object_Retain_f (gib_object_t *obj, gib_method_t *method, void *data, + gib_message_t mesg) +{ + const char *r; + + GIB_Object_Incref (obj); + r = va ("%lu", obj->handle); + GIB_Reply (mesg, 1, &r); + return 0; +} + +static int +Object_Release_f (gib_object_t *obj, gib_method_t *method, void *data, + gib_message_t mesg) +{ + GIB_Object_Decref (obj); + return 0; +} + +static int +Object_Init_f (gib_object_t *obj, gib_method_t *method, void *data, + gib_message_t mesg) +{ + const char *r; + + r = va ("%lu", obj->handle); + GIB_Reply (mesg, 1, &r); + return 0; +} + +static int +Object_Class_f (gib_object_t *obj, gib_method_t *method, void *data, + gib_message_t mesg) +{ + GIB_Reply (mesg, 1, &obj->class->name); + return 0; +} + +static int +Object_Dispose_f (gib_object_t *obj, gib_method_t *method, void *data, + gib_message_t mesg) +{ + static const char *disposed = "disposed"; + GIB_Object_Signal_Emit (obj, 1, &disposed); + GIB_Reply (mesg, 0, NULL); + return 0; +} + +static int +Object_SignalConnect_f (gib_object_t *obj, gib_method_t *method, void *data, + gib_message_t mesg) +{ + gib_object_t *other; + + if (mesg.argc >= 4 && (other = GIB_Object_Get (mesg.argv[2]))) + GIB_Object_Signal_Slot_Pair (obj, mesg.argv[1], other, + mesg.argv[3]); + GIB_Reply (mesg, 0, NULL); + return 0; +} + +static int +Object_SignalDisconnect_f (gib_object_t *obj, gib_method_t *method, void + *data, gib_message_t mesg) +{ + gib_object_t *other; + + if (mesg.argc >= 4 && (other = GIB_Object_Get (mesg.argv[2]))) + GIB_Object_Signal_Slot_Destroy (obj, mesg.argv[1], other, + mesg.argv[3]); + GIB_Reply (mesg, 0, NULL); + return 0; +} + +static int +Object_Class_New_f (gib_object_t *obj, gib_method_t *method, void *data, + gib_message_t mesg) +{ + const char *old; + gib_object_t *new; + + new = GIB_Object_Create (obj->class->name, false); + old = mesg.argv[0]; + mesg.argv[0] = "init"; + GIB_Send (new, mesg.argc, mesg.argv, mesg.reply, mesg.replydata); + mesg.argv[0] = old; + return 0; +} + +static void * +Object_Construct (gib_object_t *obj) +{ + baseobj_t *base = malloc (sizeof (baseobj_t)); + + return base; +} + +static void +Object_Destruct (void *data) +{ + free (data); + return; +} + +gib_methodtab_t Object_methods[] = { + {"retain", Object_Retain_f, NULL}, + {"release", Object_Release_f, NULL}, + {"init", Object_Init_f, NULL}, + {"class", Object_Class_f, NULL}, + {"dispose", Object_Dispose_f, NULL}, + {"signalConnect", Object_SignalConnect_f, NULL}, + {"signalDisconnect", Object_SignalDisconnect_f, NULL}, + {NULL, NULL, NULL} +}; + +gib_methodtab_t Object_class_methods[] = { + {"new", Object_Class_New_f, NULL}, + {"signalConnect", Object_SignalConnect_f, NULL}, + {"signalDisconnect", Object_SignalDisconnect_f, NULL}, + {NULL, NULL, NULL} +}; + +gib_classdesc_t Object_class = { + "Object", NULL, + Object_Construct, NULL, + Object_Destruct, + Object_methods, Object_class_methods +}; + +/* End Object class */ + + + +/* + Begin Thread class + + Creates a front end to a separate GIB buffer that is executed every frame. + The object is initialized with a GIB function and set of arguments to that + function that gets executed immediately. When the thread exits, the object + gets sent a release message. Causing the object to be destroyed before the + thread exits will immediately terminate the thread. The object can be + retained so that it is not destroyed when the thread exits on its own; in + this case, the object must be released manually later on, but otherwise + will do nothing. +*/ + +typedef struct Thread_class_s { + hashtab_t *methods; +} Thread_class_t; + +typedef struct Thread_s { + gib_object_t *obj; + cbuf_t *thread; + qboolean ended; +} Thread_t; + +static int +Thread_Init_f (gib_object_t *obj, gib_method_t *method, void *data, + gib_message_t mesg) +{ + Thread_t *t = (Thread_t *) data; + gib_function_t *f; + + if (mesg.argc < 2 || !(f = GIB_Function_Find (mesg.argv[1]))) { + GIB_Reply (mesg, 0, NULL); + GIB_Object_Destroy (obj); + return 0; + } else { + GIB_Function_Execute (t->thread, f, mesg.argv+1, mesg.argc-1); + Cbuf_Execute_Stack (t->thread); + return GIB_ForwardToSuper (mesg, obj, method); + } +} + +static void +Thread_Cbuf_Freed (cbuf_t *cbuf, void *data) +{ + Thread_t *t = (Thread_t *) data; + static const char *release = "release"; + + t->thread = NULL; + t->ended = true; + GIB_Send (t->obj, 1, &release, NULL, NULL); +} + +static void * +Thread_Construct (gib_object_t *obj) +{ + Thread_t *t = malloc (sizeof (Thread_t)); + t->thread = GIB_Thread_New (); + GIB_DATA (t->thread)->dnotify = Thread_Cbuf_Freed; + GIB_DATA (t->thread)->ddata = t; + t->obj = obj; + t->ended = false; + + return t; +} + +static void +Thread_Destruct (void *data) +{ + Thread_t *t = (Thread_t *) data; + + if (!t->ended) { + GIB_DATA (t->thread)->dnotify = NULL; + GIB_Thread_Delete (t->thread); + } + free (t); +} + +gib_methodtab_t Thread_methods[] = { + {"init", Thread_Init_f, NULL}, + {NULL, NULL, NULL} +}; + +gib_methodtab_t Thread_class_methods[] = { + {NULL, NULL, NULL} +}; + +gib_classdesc_t Thread_class = { + "Thread", "Object", + Thread_Construct, NULL, + Thread_Destruct, + Thread_methods, Thread_class_methods +}; + +/* + Scripted object class factory + + These functions and structs are used to create a class that executes + GIB functions in a new thread in response to messages. This allows classes + to be created in GIB itself. +*/ + +typedef struct Scrobj_s { + hashtab_t *shared; +} Scrobj_t; + +typedef struct Scrobj_method_s { + gib_function_t *func; +} Scrobj_method_t; + +static void * +Scrobj_Construct (gib_object_t *obj) +{ + Scrobj_t *new = malloc (sizeof (Scrobj_t)); + + new->shared = GIB_Var_Hash_New (); + + return new; +} + +static void * +Scrobj_Class_Construct (gib_object_t *obj) +{ + Scrobj_t *new = malloc (sizeof (Scrobj_t)); + + new->shared = GIB_Domain_Get (obj->class->name); + + return new; +} + +static void +Scrobj_Destruct (void *data) +{ + Scrobj_t *s = (Scrobj_t *) data; + + Hash_DelTable (s->shared); + free (s); +} + +static void +Scrobj_Thread_Died (cbuf_t *thread, void *data) +{ + GIB_Reply (GIB_DATA(thread)->reply.mesg, 0, NULL); + GIB_Object_Decref (GIB_DATA(thread)->reply.obj); +} + +static int +Scrobj_Method_f (gib_object_t *obj, gib_method_t *method, void *data, + gib_message_t mesg) +{ + static char this[] = "this"; + unsigned int ind; + cbuf_t *thread = GIB_Thread_New (); + static hashtab_t *nhash = NULL; + gib_var_t *var; + + + GIB_DATA(thread)->dnotify = Scrobj_Thread_Died; + GIB_DATA(thread)->reply.obj = obj; + GIB_DATA(thread)->reply.method = method; + GIB_DATA(thread)->reply.mesg = mesg; + GIB_Function_Execute (thread, ((Scrobj_method_t *)method->data)->func, + mesg.argv, mesg.argc); + GIB_DATA(thread)->globals = ((Scrobj_t *)data)->shared; + var = GIB_Var_Get_Complex (&GIB_DATA(thread)->locals, &nhash, this, + &ind, true); + if (obj->handle) + dsprintf (var->array[0].value, "%lu", obj->handle); + else + dstring_copystr (var->array[0].value, obj->class->name); + GIB_Object_Incref (obj); + Cbuf_Execute_Stack (thread); + + return 0; +} + +void +GIB_Classes_Build_Scripted (const char *name, const char *parentname, + gib_tree_t *tree, gib_script_t *script) +{ + gib_tree_t *line; + llist_t *methods, *cmethods; + gib_methodtab_t *mtab, *cmtab; + gib_classdesc_t desc; + enum {CLASS, INSTANCE} mode = INSTANCE; + + static void + mtabfree (void *mtab, void *unused) + { + free (mtab); + } + + static const char * + fname (const char *str) + { + if (mode == INSTANCE) + return va ("__%s_%s__", name, str); + else + return va ("%s::%s", name, str); + } + + methods = llist_new (mtabfree, NULL, NULL); + cmethods = llist_new (mtabfree, NULL, NULL); + + for (line = tree; line; line = line->next) + switch (line->type) { + case TREE_T_LABEL: + if (!strcmp (line->str, "class")) + mode = CLASS; + else if (!strcmp (line->str, "instance")) + mode = INSTANCE; + break; + case TREE_T_CMD: + if (!strcmp (line->children->str, + "function")) { + gib_methodtab_t *new = malloc (sizeof + (gib_methodtab_t)); + Scrobj_method_t *data = malloc (sizeof + (Scrobj_method_t)); + data->func = GIB_Function_Define + (fname + (line->children->next->str), + line->children->next->next->str, + line->children->next->next->children, + script, NULL); + new->data = data; + new->name = line->children->next->str; + new->func = Scrobj_Method_f; + if (mode == INSTANCE) + llist_append (methods, new); + else + llist_append (cmethods, new); + } + break; + default: + break; + } + + llist_append (methods, calloc (1, sizeof (gib_methodtab_t))); + llist_append (cmethods, calloc (1, sizeof (gib_methodtab_t))); + + mtab = llist_createarray (methods, sizeof (gib_methodtab_t)); + cmtab = llist_createarray (cmethods, sizeof (gib_methodtab_t)); + + desc.name = name; + desc.parentname = parentname; + desc.construct = Scrobj_Construct; + desc.class_construct = Scrobj_Class_Construct; + desc.destruct = Scrobj_Destruct; + desc.methods = mtab; + desc.class_methods = cmtab; + + GIB_Class_Create (&desc); + + free (mtab); + free (cmtab); + llist_delete (methods); + llist_delete (cmethods); +} + +void +GIB_Classes_Init (void) +{ + GIB_Class_Create (&Object_class); + GIB_Class_Create (&Thread_class); +} diff --git a/libs/gib/gib_execute.c b/libs/gib/gib_execute.c index 8b1d95212..3395a59f6 100644 --- a/libs/gib/gib_execute.c +++ b/libs/gib/gib_execute.c @@ -202,16 +202,21 @@ GIB_Execute (cbuf_t * cbuf) gib_buffer_data_t *g = GIB_DATA (cbuf); gib_builtin_t *b; gib_function_t *f; + gib_object_t *obj; unsigned int index; gib_var_t *var; int i; + qboolean super; + + static const char **mesg = NULL; + static int maxmesg = 0; if (!g->program) return; g->ip = g->ip ? g->ip->next : g->program; while (g->ip) { switch (g->ip->type) { - case TREE_T_NOP: // Move to next instruction + case TREE_T_LABEL: // Move to next instruction g->ip = g->ip->next; continue; case TREE_T_JUMP: // Absolute jump @@ -244,12 +249,80 @@ GIB_Execute (cbuf_t * cbuf) if (g->ip->flags & TREE_L_EMBED) { GIB_Buffer_Push_Sstack (cbuf); g->waitret = true; - for (i = 2; i < cbuf->args->argc; i++) - GIB_Return (cbuf->args->argv[i]->str); + if (GIB_CanReturn ()) + for (i = 2; i < cbuf->args->argc; i++) + GIB_Return (cbuf->args->argv[i]->str); } else g->waitret = false; g->ip = g->ip->next; continue; + case TREE_T_SEND: // Message sending + if (GIB_Execute_Prepare_Line (cbuf, g->ip)) + return; + if (cbuf->args->argc - 2 > maxmesg) { + maxmesg += 32; + mesg = realloc (mesg, sizeof (char *) * maxmesg); + } + for (i = 2; i < cbuf->args->argc; i++) + mesg[i-2] = cbuf->args->argv[i]->str; + + super = false; + if (!strcmp (cbuf->args->argv[0]->str, + "super")) { + if (!(obj = g->reply.obj)) { + GIB_Error ( + "send", + "Sending " + "message to " + "super not " + "possible in " + "this context." + ); + return; + } + super = true; + } else if (!(obj = GIB_Object_Get (cbuf->args->argv[0]->str))) { + GIB_Error ( + "send", + "No such object or class: %s", + cbuf->args->argv[0]->str + ); + return; + } + if (g->ip->flags & TREE_L_EMBED) { + // Get ready for return values + g->waitret = true; + GIB_Buffer_Push_Sstack (cbuf); + cbuf->state = CBUF_STATE_BLOCKED; + i = super ? GIB_SendToMethod (obj, + g->reply.method->parent, + i - 2, mesg, + GIB_Buffer_Reply_Callback, + cbuf) : GIB_Send (obj, + i - 2, mesg, + GIB_Buffer_Reply_Callback, + cbuf); + } else { + g->waitret = false; + i = super ? GIB_SendToMethod (obj, + g->reply.method->parent, + i - 2, mesg, + NULL, NULL) : + GIB_Send (obj, i - 2, + mesg, NULL, NULL); + } + if (i < 0) { + GIB_Error ( + "send", + "Object %s (%s) could not handle message %s", + cbuf->args->argv[0]->str, + obj->class->name, + cbuf->args->argv[2]->str + ); + return; + } + g->ip = g->ip->next; + continue; case TREE_T_CMD: // Normal command if (GIB_Execute_Prepare_Line (cbuf, g->ip)) return; @@ -278,9 +351,9 @@ GIB_Execute (cbuf_t * cbuf) cbuf->args->argv[0]->str ); } - if (cbuf->state) - return; } + if (cbuf->state) + return; g->ip = g->ip->next; continue; default: // We should never get here diff --git a/libs/gib/gib_function.c b/libs/gib/gib_function.c index 5404e3d74..e65e91142 100644 --- a/libs/gib/gib_function.c +++ b/libs/gib/gib_function.c @@ -102,7 +102,7 @@ GIB_Function_Free (void *ele, void *ptr) allocating one and adding it to the functions hash if needed. */ -void +gib_function_t * GIB_Function_Define (const char *name, const char *text, gib_tree_t * program, gib_script_t * script, hashtab_t * globals) { @@ -132,6 +132,8 @@ GIB_Function_Define (const char *name, const char *text, gib_tree_t * program, func->program = program; func->globals = globals; func->script = script; + + return func; } /* diff --git a/libs/gib/gib_handle.c b/libs/gib/gib_handle.c index 0d557c45a..9c4079096 100644 --- a/libs/gib/gib_handle.c +++ b/libs/gib/gib_handle.c @@ -38,13 +38,13 @@ static __attribute__ ((unused)) const char rcsid[] = "$Id$"; -static unsigned long int gib_next_handle, gib_next_class; +static unsigned long int gib_next_handle; static gib_handle_t *gib_unused_handles; static gib_handle_t **gib_handles; static unsigned long int gib_handles_size; unsigned long int -GIB_Handle_New (void *data, unsigned short int class) +GIB_Handle_New (gib_object_t *data) { gib_handle_t *new; if (gib_unused_handles) { @@ -60,17 +60,16 @@ GIB_Handle_New (void *data, unsigned short int class) new->num = num; } new->data = data; - new->class = class; gib_handles[new->num] = new; return new->num; } void -GIB_Handle_Free (unsigned long int num, unsigned short int class) +GIB_Handle_Free (unsigned long int num) { gib_handle_t *hand; - if (num >= gib_next_handle || gib_handles[num]->class != class) + if (num >= gib_next_handle || !gib_handles[num]) return; hand = gib_handles[num]; gib_handles[num] = 0; @@ -78,26 +77,19 @@ GIB_Handle_Free (unsigned long int num, unsigned short int class) gib_unused_handles = hand; } -void * -GIB_Handle_Get (unsigned long int num, unsigned short int class) +gib_object_t * +GIB_Handle_Get (unsigned long int num) { - if (num >= gib_next_handle || !gib_handles[num] || gib_handles[num]->class != class) + if (num >= gib_next_handle || !gib_handles[num]) return 0; return gib_handles[num]->data; } -unsigned short int -GIB_Handle_Class_New (void) -{ - return gib_next_class++; -} - void GIB_Handle_Init (void) { gib_handles_size = 256; gib_handles = calloc (gib_handles_size, sizeof (gib_handle_t *)); - gib_next_class = 0; - gib_next_handle = 0; + gib_next_handle = 1; gib_unused_handles = 0; } diff --git a/libs/gib/gib_init.c b/libs/gib/gib_init.c index 54e9b9736..b65ed2f6e 100644 --- a/libs/gib/gib_init.c +++ b/libs/gib/gib_init.c @@ -54,6 +54,7 @@ const char rcsid[] = #include "gib_builtin.h" #include "gib_thread.h" #include "gib_handle.h" +#include "gib_object.h" static void GIB_Exec_Override_f (void) @@ -109,7 +110,10 @@ GIB_Init (qboolean sandbox) GIB_Regex_Init (); // Initialize builtins GIB_Builtin_Init (sandbox); + // Initialize thread system; + GIB_Thread_Init (); // Initialize event system GIB_Event_Init (); - + // Initialize object system + GIB_Object_Init (); } diff --git a/libs/gib/gib_object.c b/libs/gib/gib_object.c new file mode 100644 index 000000000..dd35abd43 --- /dev/null +++ b/libs/gib/gib_object.c @@ -0,0 +1,374 @@ +/* + gib_object.c + + GIB object functions + + Copyright (C) 2003 Brian Koropoff + + 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 + +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include +#include + +static __attribute__ ((unused)) const char rcsid[] = + "$Id$"; + +#include "QF/hash.h" +#include "QF/sys.h" +#include "QF/va.h" +#include "QF/gib.h" +#include "gib_object.h" +#include "gib_handle.h" +#include "gib_classes.h" + +hashtab_t *gib_classes; + +/* + Hashtable callbacks +*/ +static const char * +GIB_Class_Get_Key (void *ele, void *ptr) +{ + return ((gib_class_t *) ele)->name; +} + +static void +GIB_Class_Free (void *ele, void *ptr) +{ + gib_class_t *b; + + b = (gib_class_t *) ele; + free ((void *)b->name); + free (b); +} + +static const char * +GIB_Method_Get_Key (void *ele, void *ptr) +{ + return ((gib_method_t *) ele)->name; +} + +static void +GIB_Method_Free (void *ele, void *ptr) +{ + // FIXME: Do something here +} + +static const char * +GIB_Signal_Get_Key (void *ele, void *ptr) +{ + return ((gib_signal_t *) ele)->name; +} + +static void +GIB_Signal_Free (void *ele, void *ptr) +{ + gib_signal_t *sig; + gib_slot_t *slot; + + sig = (gib_signal_t *) ele; + slot = llist_remove (llist_getnode (sig->receiver->slots, + sig->slot)); + + free ((void *)sig->name); + free ((void *)slot->mesg); + free (sig); + free (slot); +} + +// Linked list callbacks + +static void +GIB_Slot_Free (void *ele, void *ptr) +{ + gib_signal_t *sig; + gib_slot_t *slot; + + slot = (gib_slot_t *) ele; + sig = Hash_DelElement (slot->sender->signals, slot->signal); + + free ((void *)sig->name); + free ((void *)slot->mesg); + free (sig); + free (slot); +} + +static hashtab_t * +GIB_Method_Build_Hash (gib_class_t *class, hashtab_t *inherited, + gib_methodtab_t *methods) +{ + gib_methodtab_t *m; + gib_method_t *method; + hashtab_t *new = Hash_NewTable (1024, GIB_Method_Get_Key, GIB_Method_Free, 0); + + for (m = methods; m->name; m++) { + method = malloc (sizeof (gib_method_t)); + method->parent = inherited ? Hash_Find (inherited, m->name) : NULL; + method->name = strdup (m->name); + method->func = m->func; + method->data = m->data; + method->class = class; + Hash_Add (new, method); + } + + if (inherited) { + void **list; + + for (list = Hash_GetList (inherited); *list; list++) + if (!Hash_Find (new, GIB_Method_Get_Key (*list, + NULL))) + Hash_Add (new, *list); + } + + return new; +} + +void +GIB_Class_Create (gib_classdesc_t *desc) +{ + static const char *init = "init"; + gib_class_t *parent = NULL, *class = calloc (1, sizeof (gib_class_t)); + + if (desc->parentname && (parent = Hash_Find (gib_classes, desc->parentname))) { + class->parent = parent; + class->depth = parent->depth + 1; + } else + class->depth = 0; + + class->name = strdup (desc->name); + + class->construct = desc->construct; + class->class_construct = desc->class_construct; + class->destruct = desc->destruct; + class->methods = GIB_Method_Build_Hash (class, parent ? + parent->methods : NULL, desc->methods); + class->class_methods = GIB_Method_Build_Hash (class, parent ? + parent->class_methods : NULL, desc->class_methods); + + Hash_Add (gib_classes, class); + + // Create a class object + + class->classobj = GIB_Object_Create (desc->name, true); + GIB_Send (class->classobj, 1, &init, NULL, NULL); +} + +/* + GIB_Object_Create + + Creates a new object from a named class. + Does not send object an initialization + message! +*/ + +gib_object_t * +GIB_Object_Create (const char *classname, qboolean classobj) +{ + gib_class_t *temp, *class = Hash_Find (gib_classes, classname); + gib_object_t *obj; + int i; + + if (!class) + return NULL; + + obj = calloc (1, sizeof (gib_object_t)); + obj->class = class; + obj->data = malloc (sizeof (void *) * (class->depth+1)); + obj->methods = classobj ? class->class_methods : class->methods; + obj->handle = classobj ? 0 : GIB_Handle_New (obj); + obj->refs = 1; + obj->signals = Hash_NewTable (128, GIB_Signal_Get_Key, + GIB_Signal_Free, NULL); + obj->slots = llist_new (GIB_Slot_Free, NULL, NULL); + + if (classobj) { + for (temp = class, i = class->depth; temp; temp = temp->parent, i--) + if (temp->class_construct) + obj->data[i] = temp->class_construct (obj); + } else { + for (temp = class, i = class->depth; temp; temp = temp->parent, i--) + if (temp->construct) + obj->data[i] = temp->construct (obj); + } + return obj; +} + +static void +GIB_Object_Finish_Destroy (int argc, const char **argv, void *data) +{ + gib_object_t *obj = (gib_object_t *) data; + + int i; + gib_class_t *temp; + + for (temp = obj->class, i = obj->class->depth; temp; temp = temp->parent, i--) + if (temp->destruct) + temp->destruct (obj->data[i]); + free (obj->data); + GIB_Handle_Free (obj->handle); + Hash_DelTable (obj->signals); + llist_delete (obj->slots); + free (obj); +} + +/* + GIB_Object_Destroy + + Sends an object a dispose message and then frees it upon reply. +*/ + +void +GIB_Object_Destroy (gib_object_t *obj) +{ + const static char *dispose = "dispose"; + GIB_Send (obj, 1, &dispose, GIB_Object_Finish_Destroy, obj); +} + +void +GIB_Object_Incref (gib_object_t *obj) +{ + if (obj->refs > 0) + obj->refs++; +} + +void +GIB_Object_Decref (gib_object_t *obj) +{ + if (obj->refs > 0 && !--obj->refs) + GIB_Object_Destroy (obj); +} + +int +GIB_Send (gib_object_t *obj, int argc, const char **argv, gib_reply_handler reply, void *replydata) +{ + gib_message_t message; + gib_method_t *method; + + if (!(method = Hash_Find (obj->methods, *argv))) + return -1; + + message.argc = argc; + message.argv = argv; + message.reply = reply; + message.replydata = replydata; + + return method->func (obj, method, obj->data[method->class->depth], message); +} + +int +GIB_SendToMethod (gib_object_t *obj, gib_method_t *method, int argc, const char **argv, gib_reply_handler reply, void *replydata) +{ + gib_message_t message; + + message.argc = argc; + message.argv = argv; + message.reply = reply; + message.replydata = replydata; + + return method->func (obj, method, obj->data[method->class->depth], message); +} + +gib_object_t * +GIB_Object_Get (const char *id) +{ + gib_class_t *class; + + if (isdigit ((byte) *id)) + return GIB_Handle_Get (atoi (id)); + else if ((class = Hash_Find (gib_classes, id))) + return class->classobj; + else + return NULL; +} + +void +GIB_Object_Signal_Slot_Pair (gib_object_t *sender, const char *signal, + gib_object_t *receiver, const char *slot) +{ + gib_signal_t *si = malloc (sizeof (gib_signal_t)); + gib_slot_t *sl = malloc (sizeof (gib_slot_t)); + + si->slot = sl; + sl->signal = si; + + si->receiver = receiver; + sl->sender = sender; + + si->name = strdup (signal); + sl->mesg = strdup (slot); + + Hash_Add (sender->signals, si); + llist_append (receiver->slots, sl); +} + +void +GIB_Object_Signal_Slot_Destroy (gib_object_t *sender, const char *signal, + gib_object_t *receiver, const char *slot) +{ + gib_signal_t **list, **cur; + + if ((list = (gib_signal_t **) Hash_FindList (sender->signals, signal))) { + for (cur = list; *cur; cur++) { + if ((*cur)->receiver == receiver && !strcmp + ((*cur)->slot->mesg, slot)) { + Hash_Free (sender->signals, Hash_DelElement + (sender->signals, *cur)); + break; + } + } + free (list); + } +} + +void +GIB_Object_Signal_Emit (gib_object_t *sender, int argc, const char **argv) +{ + gib_signal_t **list, **cur; + const char *old = *argv; + + if ((list = (gib_signal_t **) Hash_FindList (sender->signals, *argv))) { + for (cur = list; *cur; cur++) { + *argv = (*cur)->slot->mesg; + GIB_Send ((*cur)->receiver, argc, argv, NULL, NULL); + } + free (list); + } + *argv = old; +} + +void +GIB_Object_Init (void) +{ + gib_classes = Hash_NewTable (1024, GIB_Class_Get_Key, GIB_Class_Free, 0); + + GIB_Classes_Init (); +} diff --git a/libs/gib/gib_semantics.c b/libs/gib/gib_semantics.c index 3dca2f885..25daf9fa3 100644 --- a/libs/gib/gib_semantics.c +++ b/libs/gib/gib_semantics.c @@ -35,6 +35,80 @@ #include "gib_parse.h" #include "gib_semantics.h" +static int +GIB_Semantic_Validate_Class (gib_tree_t * tokens) +{ + gib_tree_t *a_class, *line, *cmd; + + if (!tokens->next || !tokens->next->next) { + GIB_Parse_Error ("Malformed class definition; expected class " + "name, optional colon and parent class, and " + "program block.", tokens->start); + return -1; + } + + if (tokens->next->next->delim == ' ' && !strcmp + (tokens->next->next->str, ":")) { + if (!tokens->next->next->next) { + GIB_Parse_Error ("Malformed class definition; " + "expected parent class after " + "\":\".", tokens->next->next->start); + return -1; + } + a_class = tokens->next->next->next->next; + } else + a_class = tokens->next->next; + + if (!a_class || !a_class->children || a_class->delim != '{') { + GIB_Parse_Error ("Malformed class definition; expected " + "program block.", tokens->next->next->start); + return -1; + } + + for (line = a_class->children; line; line = line->next) { + switch (line->type) { + case TREE_T_LABEL: + if (strcmp (line->str, "class") && strcmp + (line->str, "instance")) { + GIB_Parse_Error ("Malformed class " + "definition; allowed " + "labels are instance " + "and class.", + line->start); + return -1; + } + break; + case TREE_T_CMD: + cmd = line->children; + if (strcmp (cmd->str, "function")) { + GIB_Parse_Error ("Malformed class " + "definition; only " + "allowed command is " + "function.", + cmd->start); + return -1; + } else if (!cmd->next || !cmd->next->next || + cmd->next->next->delim != '{' + || !cmd->next->next->children) { + GIB_Parse_Error ("Malformed function " + "definition; name, " + "program block " + "expected.", + cmd->start); + return -1; + } + break; + default: + GIB_Parse_Error ("Malformed class " + "definition; only commands " + "and labels allowed.", + line->start); + return -1; + break; + } + } + return 0; +} static gib_tree_t * GIB_Semantic_Normal_To_Lines (gib_tree_t * tokens, const char *program, gib_tree_flags_t flags, unsigned int start, unsigned int end) { @@ -72,11 +146,25 @@ GIB_Semantic_Normal_To_Lines (gib_tree_t * tokens, const char *program, gib_tree mainline->flags = flags; mainline->start = start; mainline->end = end; - mainline->children = tokens; // Check for assignment if (tokens->next && tokens->next->delim == ' ' && !strcmp (tokens->next->str, "=")) mainline->type = TREE_T_ASSIGN; + // Check for message sending + else if (tokens->next && tokens->next->delim == ' ' && !strcmp (tokens->next->str, "->")) { + if (!tokens->next->next) { + GIB_Tree_Unref (&mainline); + GIB_Parse_Error ("Cannot send empty message.", token->next->start); + return NULL; + } else + mainline->type = TREE_T_SEND; + // Check for class definition, validate + } else if (!strcmp (tokens->str, "class") && + GIB_Semantic_Validate_Class (tokens)) { + GIB_Tree_Unref (&mainline); + return NULL; + } + mainline->children = tokens; return lines; } @@ -252,7 +340,7 @@ GIB_Semantic_While_To_Lines (gib_tree_t *tokens, const char *program, gib_tree_f next = &conditional->next; // Create end point (for 'break' commands) - endp = GIB_Tree_New (TREE_T_NOP); + endp = GIB_Tree_New (TREE_T_LABEL); // Move program block inline *next = a_block->children; @@ -358,7 +446,7 @@ GIB_Semantic_For_To_Lines (gib_tree_t *tokens, const char *program, gib_tree_fla *next = a_block->children; a_block->children = 0; - endp = GIB_Tree_New (TREE_T_NOP); + endp = GIB_Tree_New (TREE_T_LABEL); // Find end of program block for (temp = *next; temp->next; temp = temp->next) { @@ -384,7 +472,25 @@ GIB_Semantic_For_To_Lines (gib_tree_t *tokens, const char *program, gib_tree_fla return lines; } +static gib_tree_t * +GIB_Semantic_Label_To_Lines (gib_tree_t *tokens, const char *program, + gib_tree_flags_t flags) +{ + gib_tree_t *line; + char *name; + line = GIB_Tree_New (TREE_T_LABEL); + + name = strdup (tokens->str); + name[strlen(name)-1] = '\0'; + line->str = name; + line->flags = flags; + + GIB_Tree_Unref (&tokens); + + return line; +} + gib_tree_t * GIB_Semantic_Tokens_To_Lines (gib_tree_t *tokens, const char *program, gib_tree_flags_t flags, unsigned int start, unsigned int end) { @@ -399,7 +505,7 @@ GIB_Semantic_Tokens_To_Lines (gib_tree_t *tokens, const char *program, gib_tree_ // Create landing pad where all program blocks in // a chained if/else structure will jump to after // completing so that only one block is executed. - endp = GIB_Tree_New (TREE_T_NOP); + endp = GIB_Tree_New (TREE_T_LABEL); do { // Link in output from if statement handler *next = GIB_Semantic_If_To_Lines (&tokens, program, flags, endp); @@ -419,6 +525,8 @@ GIB_Semantic_Tokens_To_Lines (gib_tree_t *tokens, const char *program, gib_tree_ *next = GIB_Semantic_While_To_Lines (tokens, program, flags); else if (!strcmp (tokens->str, "for")) *next = GIB_Semantic_For_To_Lines (tokens, program, flags); + else if (tokens->str[strlen(tokens->str)-1] == ':' && !tokens->next) + *next = GIB_Semantic_Label_To_Lines (tokens, program, flags); else *next = GIB_Semantic_Normal_To_Lines (tokens, program, flags, start, end); next = &(*next)->next; diff --git a/libs/gib/gib_thread.c b/libs/gib/gib_thread.c index 95c922f20..70b8e546c 100644 --- a/libs/gib/gib_thread.c +++ b/libs/gib/gib_thread.c @@ -44,88 +44,67 @@ const char rcsid[] = "$Id$"; #include "QF/gib.h" #include "QF/dstring.h" #include "QF/hash.h" +#include "QF/llist.h" #include "gib_handle.h" #include "gib_tree.h" #include "gib_function.h" #include "gib_thread.h" -gib_thread_t *gib_thread_first = 0; -gib_thread_t *gib_thread_last = 0; - -unsigned short int gib_thread_class; - +llist_t *gib_threads; hashtab_t *gib_events; -void -GIB_Thread_Add (gib_thread_t * thread) +static void +GIB_Thread_Free (void *ele, void *data) { - if (!gib_thread_first) - gib_thread_first = thread; - - thread->prev = gib_thread_last; - if (!gib_thread_last) - gib_thread_last = thread; - else { - gib_thread_last->next = thread; - gib_thread_last = thread; - } + Cbuf_DeleteStack ((cbuf_t *) ele); } -void -GIB_Thread_Remove (gib_thread_t * thread) -{ - if (thread->prev) - thread->prev->next = thread->next; - else - gib_thread_first = thread->next; - if (thread->next) - thread->next->prev = thread->prev; - else - gib_thread_last = thread->prev; -} - -gib_thread_t * +cbuf_t * GIB_Thread_New (void) { - gib_thread_t *new = calloc (1, sizeof (gib_thread_t)); - - new->cbuf = Cbuf_New (GIB_Interpreter ()); - new->id = GIB_Handle_New (new, gib_thread_class); + cbuf_t *new = Cbuf_New (GIB_Interpreter ()); + llist_append (gib_threads, new); return new; } void -GIB_Thread_Delete (gib_thread_t * thread) +GIB_Thread_Delete (cbuf_t *thread) { - Cbuf_DeleteStack (thread->cbuf); - GIB_Handle_Free (thread->id, gib_thread_class); - free (thread); + cbuf_t *temp; + + for (temp = thread; temp->down && temp->down->state != CBUF_STATE_JUNK; temp = temp->down); + if (temp == cbuf_active) + temp->state = CBUF_STATE_ERROR; + else + llist_remove (llist_getnode (gib_threads, thread)); +} + +unsigned int +GIB_Thread_Count (void) +{ + return llist_size (gib_threads); } void GIB_Thread_Execute (void) { - gib_thread_t *cur, *tmp; - - if (!gib_thread_first) - return; - - for (cur = gib_thread_first; cur; cur = tmp) { - tmp = cur->next; - if (GIB_DATA(cur->cbuf)->program) - Cbuf_Execute_Stack (cur->cbuf); - else { - GIB_Thread_Remove (cur); - GIB_Thread_Delete (cur); - } + static qboolean iterator (cbuf_t *cbuf, llist_node_t *node) + { + if (GIB_DATA(cbuf)->program) + Cbuf_Execute_Stack (cbuf); + else + Cbuf_DeleteStack ((cbuf_t *) llist_remove (node)); + return true; } + + llist_iterate (gib_threads, LLIST_ICAST (iterator)); } void GIB_Thread_Init (void) { - gib_thread_class = GIB_Handle_Class_New (); + gib_threads = llist_new (GIB_Thread_Free, NULL, NULL); } static const char * @@ -169,7 +148,7 @@ void GIB_Event_Callback (gib_event_t * event, unsigned int argc, ...) { gib_function_t *f = event->func; - gib_thread_t *thread; + cbuf_t *thread; cbuf_args_t *args; va_list ap; unsigned int i; @@ -188,8 +167,7 @@ GIB_Event_Callback (gib_event_t * event, unsigned int argc, ...) va_end (ap); - GIB_Function_Execute_D (thread->cbuf, f, args->argv, args->argc); - GIB_Thread_Add (thread); + GIB_Function_Execute_D (thread, f, args->argv, args->argc); Cbuf_ArgsDelete (args); } diff --git a/libs/gib/gib_vars.c b/libs/gib/gib_vars.c index 9741b1221..f22a8b4c4 100644 --- a/libs/gib/gib_vars.c +++ b/libs/gib/gib_vars.c @@ -302,6 +302,12 @@ GIB_Domain_Get (const char *name) return d->vars; } +hashtab_t * +GIB_Var_Hash_New (void) +{ + return Hash_NewTable (1024, GIB_Var_Get_Key, GIB_Var_Free, 0); +} + void GIB_Var_Init (void) { diff --git a/libs/util/cbuf.c b/libs/util/cbuf.c index c9309a6a1..e17ccbaf5 100644 --- a/libs/util/cbuf.c +++ b/libs/util/cbuf.c @@ -51,7 +51,7 @@ static __attribute__ ((unused)) const char rcsid[] = #include "compat.h" -cbuf_t *cbuf_active; +cbuf_t *cbuf_active = NULL; cbuf_args_t * Cbuf_ArgsNew (void) @@ -175,8 +175,10 @@ Cbuf_InsertText (cbuf_t *cbuf, const char *text) void Cbuf_Execute (cbuf_t *cbuf) { + cbuf_t *old = cbuf_active; cbuf_active = cbuf; cbuf->interpreter->execute (cbuf); + cbuf_active = old; } void @@ -191,6 +193,8 @@ Cbuf_Execute_Stack (cbuf_t *cbuf) return; } for (sp = cbuf; sp->down && sp->down->state != CBUF_STATE_JUNK; sp = sp->down); + if (sp->state == CBUF_STATE_BLOCKED) + return; while (sp) { Cbuf_Execute (sp); if (sp->state) { @@ -200,6 +204,8 @@ Cbuf_Execute_Stack (cbuf_t *cbuf) continue; } else if (sp->state == CBUF_STATE_ERROR) break; + else if (sp->state == CBUF_STATE_BLOCKED) + return; else { sp->state = CBUF_STATE_NORMAL; return; diff --git a/libs/util/llist.c b/libs/util/llist.c index 74832612a..128053d37 100644 --- a/libs/util/llist.c +++ b/libs/util/llist.c @@ -28,6 +28,12 @@ #ifdef HAVE_CONFIG_H # include "config.h" #endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif #include @@ -195,6 +201,19 @@ llist_remove (llist_node_t *ref) return element; } +unsigned int +llist_size (llist_t *llist) +{ + unsigned int i; + llist_node_t *n; + + if (!llist->start) + return 0; + else for (i = 0, n = llist->start; n; n = n->next, i++); + + return i; +} + void llist_iterate (llist_t *list, llist_iterator_t iterate) { @@ -228,7 +247,7 @@ llist_findnode (llist_t *list, void *comparison) { llist_node_t *node; - if (!list) + if (!list || !list->cmpdata) return 0; for (node = list->start; node; node = node->next) if (list->cmpdata (node->data, comparison, list->userdata)) @@ -236,3 +255,15 @@ llist_findnode (llist_t *list, void *comparison) return 0; } +void * +llist_createarray (llist_t *list, size_t esize) +{ + void *ptr, *array = malloc (llist_size (list) * esize); + llist_node_t *node; + + for (ptr = array, node = list->start; node; node = node->next, ptr += + esize) + memcpy (ptr, node->data, esize); + + return array; +} diff --git a/nq/source/Makefile.am b/nq/source/Makefile.am index bdd371200..e3d5265c5 100644 --- a/nq/source/Makefile.am +++ b/nq/source/Makefile.am @@ -74,8 +74,8 @@ common_LIBFILES= \ $(top_builddir)/libs/gamecode/builtins/libQFgamecode_builtins.la \ $(top_builddir)/libs/gamecode/engine/libQFgamecode.la \ $(top_builddir)/libs/image/libQFimage.la \ - $(top_builddir)/libs/util/libQFutil.la \ - $(top_builddir)/libs/gib/libQFgib.la + $(top_builddir)/libs/gib/libQFgib.la \ + $(top_builddir)/libs/util/libQFutil.la client_LIBS= $(client_LIBFILES) $(common_LIBFILES) diff --git a/qw/source/Makefile.am b/qw/source/Makefile.am index feeba3c40..a12237bf1 100644 --- a/qw/source/Makefile.am +++ b/qw/source/Makefile.am @@ -80,8 +80,8 @@ qf_server_LIBS= \ $(top_builddir)/libs/gamecode/builtins/libQFgamecode_builtins.la \ $(top_builddir)/libs/gamecode/engine/libQFgamecode.la \ $(top_builddir)/libs/console/libQFconsole.la \ - $(top_builddir)/libs/util/libQFutil.la \ - $(top_builddir)/libs/gib/libQFgib.la + $(top_builddir)/libs/gib/libQFgib.la \ + $(top_builddir)/libs/util/libQFutil.la qw_server_SOURCES= sv_model.c qw_server_LDADD= libqw_server.a libqw_common.a libasm.a $(qf_server_LIBS) $(NET_LIBS) $(DL_LIBS) $(CURSES_LIBS) diff --git a/ruamoko/cl_menu/HUD.h b/ruamoko/cl_menu/HUD.h index 27673012f..8481e7b12 100644 --- a/ruamoko/cl_menu/HUD.h +++ b/ruamoko/cl_menu/HUD.h @@ -9,7 +9,6 @@ integer handle; } -+ (void) initClass; - (id) initWithComponents: (integer) x : (integer) y; - (void) dealloc; - (integer) handle; diff --git a/ruamoko/cl_menu/HUD.r b/ruamoko/cl_menu/HUD.r index fef55c3b0..3c21e9017 100644 --- a/ruamoko/cl_menu/HUD.r +++ b/ruamoko/cl_menu/HUD.r @@ -8,17 +8,11 @@ integer HUDHandleClass; @implementation HUDObject -+ (void) initClass -{ - HUDHandleClass = GIB_Handle_Class_New (); -} - - (id) initWithComponents: (integer) x : (integer) y { self = [super init]; origin = [[Point alloc] initWithComponents: x :y]; visible = YES; - handle = GIB_Handle_New (self, HUDHandleClass); return self; } @@ -26,7 +20,6 @@ integer HUDHandleClass; - (void) dealloc { [origin dealloc]; - GIB_Handle_Free (handle, HUDHandleClass); [super dealloc]; } diff --git a/ruamoko/cl_menu/client_menu.qc b/ruamoko/cl_menu/client_menu.qc index 4aceffdff..d9ad17c43 100644 --- a/ruamoko/cl_menu/client_menu.qc +++ b/ruamoko/cl_menu/client_menu.qc @@ -508,5 +508,4 @@ void () menu_init = Menu_TopMenu ("main"); Menu_SetQuit (quit); - HUD_Init (); }; diff --git a/ruamoko/cl_menu/hud_interface.qc b/ruamoko/cl_menu/hud_interface.qc index 6c753d051..47276f261 100644 --- a/ruamoko/cl_menu/hud_interface.qc +++ b/ruamoko/cl_menu/hud_interface.qc @@ -5,271 +5,7 @@ #include "string.h" #include "debug.h" -@static Array HUDObjects; - -void (integer argc, string [] argv) gib_hud_new_text_f = -{ - local HUDObject newText; - - if (argc != 4) - return; - - newText = [[HUDText alloc] initWithComponents - :stoi (argv[1]) - :stoi (argv[2]) - :argv[3] - ]; - - [HUDObjects addItem :newText]; - - GIB_Return (itos ([newText handle])); -}; - -void (integer argc, string [] argv) gib_hud_new_graphic_f = -{ - local HUDGraphic newGraphic; - - if (argc != 4) - return; - - newGraphic = [[HUDGraphic alloc] initWithComponents - :stoi (argv[1]) - :stoi (argv[2]) - :argv[3] - ]; - - [HUDObjects addItem :newGraphic]; - - GIB_Return (itos ([newGraphic handle])); -}; - -void (integer argc, string [] argv) gib_hud_new_anim_f = -{ - local HUDAnimation newAnim; - local Frame frame; - local integer i; - - if (argc < 5) - return; - - newAnim = [[HUDAnimation alloc] initWithComponents - :stoi (argv[1]) - :stoi (argv[2]) - ]; - - for (i = 3; i < argc; i += 2) { - frame = [[Frame alloc] initWithFile: argv[i] duration: stof (argv[i+1])]; - [newAnim addFrame :frame]; - } - [HUDObjects addItem :newAnim]; - - GIB_Return (itos ([newAnim handle])); -}; - -void (integer argc, string [] argv) gib_hud_start_anim_f = -{ - local integer i; - local HUDAnimation anim; - - if (argc < 2) - return; - - for (i = 1; i < argc; i++) { - anim = GIB_Handle_Get (stoi (argv[i]), HUDHandleClass); - if (anim && [anim isKindOfClass :[HUDAnimation class]]) - [anim start]; - } -}; - -void (integer argc, string [] argv) gib_hud_stop_anim_f = -{ - local integer i; - local HUDAnimation anim; - - if (argc < 2) - return; - - for (i = 1; i < argc; i++) { - anim = GIB_Handle_Get (stoi (argv[i]), HUDHandleClass); - if (anim && [anim isKindOfClass :[HUDAnimation class]]) - [anim stop]; - } -}; - -void (integer argc, string [] argv) gib_hud_set_looping_f = -{ - local HUDAnimation anim; - - if (argc < 3) - return; - - anim = GIB_Handle_Get (stoi (argv[1]), HUDHandleClass); - if (anim && [anim isKindOfClass :[HUDAnimation class]]) { - switch (argv[2]) { - case "yes": - case "true": - [anim setLooping :YES]; - break; - case "no": - case "false": - [anim setLooping :NO]; - break; - default: - break; - } - } -}; - -void (integer argc, string [] argv) gib_hud_delete_f = -{ - local integer i; - local HUDObject trashObject; - - if (argc < 2) - return; - - for (i = 1; i < argc; i++) { - trashObject = GIB_Handle_Get (stoi (argv[i]), HUDHandleClass); - if (trashObject) { - [HUDObjects removeItem :trashObject]; - [trashObject dealloc]; - } else - dprint (sprintf ("Warning: no HUD object associated with handle %i\n", stoi (argv[i]))); - } -}; - -void (integer argc, string [] argv) gib_hud_get_rect_f = -{ - local HUDObject myObject; - local Point myPoint; - - if (argc != 2) - return; - - myObject = GIB_Handle_Get (stoi (argv[1]), HUDHandleClass); - if (!myObject) - return; - - myPoint = [myObject origin]; - GIB_Return (itos ([myPoint x])); - GIB_Return (itos ([myPoint y])); - myPoint = [myObject size]; - GIB_Return (itos ([myPoint x])); - GIB_Return (itos ([myPoint y])); - [myPoint dealloc]; -}; - - -void (integer argc, string [] argv) gib_hud_set_translate_f = -{ - local integer i; - local Point p; - - if (argc < 4) - return; - - p = [[Point alloc] initWithComponents :stoi (argv[argc-2]) :stoi (argv[argc-1])]; - - if (argv[0] == "HUD::translate") - for (i = 1; i < argc - 2; i++) - [(HUDObject) GIB_Handle_Get (stoi (argv[i]), HUDHandleClass) translate :p]; - else - for (i = 1; i < argc - 2; i++) - [(HUDObject) GIB_Handle_Get (stoi (argv[i]), HUDHandleClass) setOrigin :p]; - [p dealloc]; -}; - -void (integer argc, string [] argv) gib_hud_set_text_f = -{ - local HUDText myObject; - - if (argc != 3) - return; - - myObject = GIB_Handle_Get (stoi (argv[1]), HUDHandleClass); - if (!myObject || ![myObject isKindOfClass :[HUDText class]]) - return; - [myObject setText :argv[2]]; -}; - -void (integer argc, string [] argv) gib_hud_set_file_f = -{ - local HUDGraphic myObject; - - if (argc != 3) - return; - - myObject = GIB_Handle_Get (stoi (argv[1]), HUDHandleClass); - if (!myObject || ![myObject isKindOfClass :[HUDGraphic class]]) - return; - [myObject setFile :argv[2]]; -}; - -void (integer argc, string [] argv) gib_hud_show_f = -{ - local integer i; - local HUDObject object; - - if (argc < 2) - return; - - for (i = 1; i < argc; i++) { - object = GIB_Handle_Get (stoi (argv[i]), HUDHandleClass); - if (object) - [object setVisible :YES]; - else - dprint (sprintf ("Warning: no HUD object associated with handle %i\n", stoi (argv[i]))); - } -}; - -void (integer argc, string [] argv) gib_hud_hide_f = -{ - local integer i; - local HUDObject object; - - if (argc < 2) - return; - - for (i = 1; i < argc; i++) { - object = GIB_Handle_Get (stoi (argv[i]), HUDHandleClass); - if (object) - [object setVisible :NO]; - else - dprint (sprintf ("Warning: no HUD object associated with handle %i\n", stoi (argv[i]))); - } -}; - -void () HUD_Init = -{ - GIB_Builtin_Add ("HUD::newText", gib_hud_new_text_f); - GIB_Builtin_Add ("HUD::newGraphic", gib_hud_new_graphic_f); - GIB_Builtin_Add ("HUD::newAnim", gib_hud_new_anim_f); - GIB_Builtin_Add ("HUD::delete", gib_hud_delete_f); - GIB_Builtin_Add ("HUD::show", gib_hud_show_f); - GIB_Builtin_Add ("HUD::hide", gib_hud_hide_f); - GIB_Builtin_Add ("HUD::getRect", gib_hud_get_rect_f); - GIB_Builtin_Add ("HUD::setOrigin", gib_hud_set_translate_f); - GIB_Builtin_Add ("HUD::translate", gib_hud_set_translate_f); - GIB_Builtin_Add ("HUD::setText", gib_hud_set_text_f); - GIB_Builtin_Add ("HUD::setFile", gib_hud_set_file_f); - GIB_Builtin_Add ("HUD::startAnim", gib_hud_start_anim_f); - GIB_Builtin_Add ("HUD::stopAnim", gib_hud_stop_anim_f); - GIB_Builtin_Add ("HUD::setLooping", gib_hud_set_looping_f); - - // Initialize HUDObject class - [HUDObject initClass]; - - // Create array of HUD objects - HUDObjects = [[Array alloc] init]; -}; - void () menu_draw_hud = { - local integer i; - local HUDObject myHUDObject; - - for (i = 0; i < [HUDObjects count]; i++) { - myHUDObject = [HUDObjects getItemAt :i]; - [myHUDObject display]; - } }; + diff --git a/ruamoko/include/gib.h b/ruamoko/include/gib.h index 12c48d36b..67e13e929 100644 --- a/ruamoko/include/gib.h +++ b/ruamoko/include/gib.h @@ -3,9 +3,5 @@ @extern void (string name, void (integer argc, string [] argv) func) GIB_Builtin_Add; @extern integer (string value) GIB_Return; -@extern integer (void) GIB_Handle_Class_New = #0; -@extern integer (void [] data, integer class) GIB_Handle_New = #0; -@extern void [] (integer handle, integer class) GIB_Handle_Get = #0; -@extern void (integer handle, integer class) GIB_Handle_Free = #0; #endif//__ruamoko_gib_h diff --git a/ruamoko/lib/gib.r b/ruamoko/lib/gib.r index 0f7efffae..7dabb5975 100644 --- a/ruamoko/lib/gib.r +++ b/ruamoko/lib/gib.r @@ -2,7 +2,3 @@ void (string name, void (integer argc, string [] argv) func) GIB_Builtin_Add = #0; integer (string value) GIB_Return = #0; -integer (void) GIB_Handle_Class_New = #0; -integer (void [] data, integer class) GIB_Handle_New = #0; -void [] (integer handle, integer class) GIB_Handle_Get = #0; -void (integer handle, integer class) GIB_Handle_Free = #0; diff --git a/tools/carne/main.c b/tools/carne/main.c index 9df1b4f95..aa3d76519 100644 --- a/tools/carne/main.c +++ b/tools/carne/main.c @@ -17,8 +17,6 @@ #include "gib_thread.h" #include "gib_parse.h" -extern gib_thread_t *gib_threads; - static qboolean carne_done = false; static int carne_exitcode = 0; @@ -115,7 +113,8 @@ main (int argc, char **argv) // Initialize required QF subsystems Cvar_Init_Hash (); Cmd_Init_Hash (); - Cmd_Init (); + Cmd_Init (); + Cvar_Init (); GIB_Init (false); // No sandbox GIB_Builtin_Add ("exit", Carne_GIB_Exit_f);