From 687a0845b6c29a7aa82e7df621960f959ae3f221 Mon Sep 17 00:00:00 2001 From: Brian Koropoff Date: Thu, 11 Sep 2003 06:03:13 +0000 Subject: [PATCH] Introducing the GIB Object System (TM). This breaks scriptable HUD for now and probably has enough bugs to leave the Orkin man scratching his head, but it works and allows you to do neat things like write classes in GIB (amazing!) and subclass builtin classes (which are Object and Thread at the moment, Hash should be coming soon as a replacement for stem and leaf variables). --- include/Makefile.am | 4 +- include/QF/cbuf.h | 1 + include/QF/gib.h | 105 ++++++- include/QF/llist.h | 3 +- include/gib_buffer.h | 1 + include/gib_classes.h | 38 +++ include/gib_function.h | 2 +- include/gib_handle.h | 4 +- include/gib_object.h | 36 +++ include/gib_thread.h | 16 +- include/gib_tree.h | 3 +- include/gib_vars.h | 1 + libs/gamecode/builtins/bi_gib.c | 32 +-- libs/gib/Makefile.am | 4 +- libs/gib/gib_buffer.c | 17 +- libs/gib/gib_builtin.c | 123 ++++----- libs/gib/gib_classes.c | 461 +++++++++++++++++++++++++++++++ libs/gib/gib_execute.c | 83 +++++- libs/gib/gib_function.c | 4 +- libs/gib/gib_handle.c | 24 +- libs/gib/gib_init.c | 6 +- libs/gib/gib_object.c | 374 +++++++++++++++++++++++++ libs/gib/gib_semantics.c | 116 +++++++- libs/gib/gib_thread.c | 90 +++--- libs/gib/gib_vars.c | 6 + libs/util/cbuf.c | 8 +- libs/util/llist.c | 33 ++- nq/source/Makefile.am | 4 +- qw/source/Makefile.am | 4 +- ruamoko/cl_menu/HUD.h | 1 - ruamoko/cl_menu/HUD.r | 7 - ruamoko/cl_menu/client_menu.qc | 1 - ruamoko/cl_menu/hud_interface.qc | 266 +----------------- ruamoko/include/gib.h | 4 - ruamoko/lib/gib.r | 4 - tools/carne/main.c | 5 +- 36 files changed, 1402 insertions(+), 489 deletions(-) create mode 100644 include/gib_classes.h create mode 100644 include/gib_object.h create mode 100644 libs/gib/gib_classes.c create mode 100644 libs/gib/gib_object.c 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);