mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-01-17 22:50:51 +00:00
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).
This commit is contained in:
parent
f28cc3e8ec
commit
687a0845b6
36 changed files with 1402 additions and 489 deletions
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
|
|
105
include/QF/gib.h
105
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
38
include/gib_classes.h
Normal file
38
include/gib_classes.h
Normal file
|
@ -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
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
36
include/gib_object.h
Normal file
36
include/gib_object.h
Normal file
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
461
libs/gib/gib_classes.c
Normal file
461
libs/gib/gib_classes.c
Normal file
|
@ -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 <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#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);
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
|
|
374
libs/gib/gib_object.c
Normal file
374
libs/gib/gib_object.c
Normal file
|
@ -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 <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
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 ();
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -28,6 +28,12 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
integer handle;
|
||||
}
|
||||
|
||||
+ (void) initClass;
|
||||
- (id) initWithComponents: (integer) x : (integer) y;
|
||||
- (void) dealloc;
|
||||
- (integer) handle;
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
@ -508,5 +508,4 @@ void () menu_init =
|
|||
Menu_TopMenu ("main");
|
||||
Menu_SetQuit (quit);
|
||||
|
||||
HUD_Init ();
|
||||
};
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue