mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-05 20:50:43 +00:00
37a64e59ab
of using a colon to specify a parent class in a GIB class definition, "extends" is now used. If no parent class is specified, it now defaults to Object.
708 lines
16 KiB
C
708 lines
16 KiB
C
/*
|
|
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 {
|
|
unsigned long int ref;
|
|
} baseobj_t;
|
|
|
|
static int
|
|
Object_Retain_f (gib_object_t *obj, gib_method_t *method, void *data,
|
|
gib_object_t *sender, gib_message_t mesg)
|
|
{
|
|
baseobj_t *base = data;
|
|
|
|
base->ref++;
|
|
GIB_Object_Incref (obj);
|
|
GIB_Reply (obj, mesg, 1, &obj->handstr);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
Object_Release_f (gib_object_t *obj, gib_method_t *method, void *data,
|
|
gib_object_t *sender, gib_message_t mesg)
|
|
{
|
|
baseobj_t *base = data;
|
|
if (base->ref) {
|
|
base->ref--;
|
|
GIB_Object_Decref (obj);
|
|
}
|
|
GIB_Reply (obj, mesg, 0, NULL);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
Object_Init_f (gib_object_t *obj, gib_method_t *method, void *data,
|
|
gib_object_t *sender, gib_message_t mesg)
|
|
{
|
|
GIB_Reply (obj, mesg, 1, &obj->handstr);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
Object_Class_f (gib_object_t *obj, gib_method_t *method, void *data,
|
|
gib_object_t *sender, gib_message_t mesg)
|
|
{
|
|
GIB_Reply (obj, mesg, 1, &obj->class->name);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
Object_SuperClass_f (gib_object_t *obj, gib_method_t *method, void *data,
|
|
gib_object_t *sender, gib_message_t mesg)
|
|
{
|
|
if (obj->class->parent)
|
|
GIB_Reply (obj, mesg, 1, &obj->class->parent->name);
|
|
else
|
|
GIB_Reply (obj, mesg, 0, NULL);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
Object_IsKindOf_f (gib_object_t *obj, gib_method_t *method, void *data,
|
|
gib_object_t *sender, gib_message_t mesg)
|
|
{
|
|
gib_class_t *c;
|
|
static const char *one = "1";
|
|
static const char *zero = "0";
|
|
|
|
if (mesg.argc < 2)
|
|
return -1;
|
|
|
|
for (c = obj->class; c; c = c->parent)
|
|
if (!strcmp (mesg.argv[1], c->name)) {
|
|
GIB_Reply (obj, mesg, 1, &one);
|
|
return 0;
|
|
}
|
|
GIB_Reply (obj, mesg, 1, &zero);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
Object_Dispose_f (gib_object_t *obj, gib_method_t *method, void *data,
|
|
gib_object_t *sender, gib_message_t mesg)
|
|
{
|
|
static const char *disposed = "disposed";
|
|
GIB_Object_Signal_Emit (obj, 1, &disposed);
|
|
GIB_Reply (obj, mesg, 0, NULL);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
Object_SignalConnect_f (gib_object_t *obj, gib_method_t *method, void *data,
|
|
gib_object_t *sender, 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 (obj, mesg, 0, NULL);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
Object_SignalDisconnect_f (gib_object_t *obj, gib_method_t *method, void
|
|
*data, gib_object_t *sender, 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 (obj, mesg, 0, NULL);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
Object_Class_New_f (gib_object_t *obj, gib_method_t *method, void *data,
|
|
gib_object_t *sender, 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, sender, mesg.argc, mesg.argv, mesg.reply, mesg.replydata);
|
|
GIB_Object_Decref (obj);
|
|
mesg.argv[0] = old;
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
Object_Class_Children_f (gib_object_t *obj, gib_method_t *method, void *data,
|
|
gib_object_t *sender, gib_message_t mesg)
|
|
{
|
|
const char **reply;
|
|
unsigned int size;
|
|
unsigned int i = 0;
|
|
|
|
static qboolean
|
|
iterator (gib_class_t *class, void *unused)
|
|
{
|
|
reply[i++] = class->name;
|
|
return false;
|
|
}
|
|
|
|
size = llist_size (obj->class->children);
|
|
if (size) {
|
|
reply = malloc (sizeof (char *) * size);
|
|
llist_iterate (obj->class->children, LLIST_ICAST (iterator));
|
|
GIB_Reply (obj, mesg, size, reply);
|
|
} else
|
|
GIB_Reply (obj, mesg, 0, NULL);
|
|
return 0;
|
|
}
|
|
|
|
static void *
|
|
Object_Construct (gib_object_t *obj)
|
|
{
|
|
baseobj_t *base = malloc (sizeof (baseobj_t));
|
|
|
|
base->ref = 1;
|
|
|
|
return base;
|
|
}
|
|
|
|
static void
|
|
Object_Destruct (void *data)
|
|
{
|
|
free (data);
|
|
return;
|
|
}
|
|
|
|
static 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},
|
|
{"superClass", Object_SuperClass_f, NULL},
|
|
{"isKindOf", Object_IsKindOf_f, NULL},
|
|
{"dispose", Object_Dispose_f, NULL},
|
|
{"signalConnect", Object_SignalConnect_f, NULL},
|
|
{"signalDisconnect", Object_SignalDisconnect_f, NULL},
|
|
{NULL, NULL, NULL}
|
|
};
|
|
|
|
static gib_methodtab_t Object_class_methods[] = {
|
|
{"parent", Object_SuperClass_f, NULL},
|
|
{"children", Object_Class_Children_f, NULL},
|
|
{"new", Object_Class_New_f, NULL},
|
|
{"signalConnect", Object_SignalConnect_f, NULL},
|
|
{"signalDisconnect", Object_SignalDisconnect_f, NULL},
|
|
{NULL, NULL, NULL}
|
|
};
|
|
|
|
static 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_object_t *sender, 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_Object_Destroy (obj);
|
|
return -1;
|
|
} 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, 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);
|
|
}
|
|
|
|
static gib_methodtab_t Thread_methods[] = {
|
|
{"init", Thread_Init_f, NULL},
|
|
{NULL, NULL, NULL}
|
|
};
|
|
|
|
static gib_methodtab_t Thread_class_methods[] = {
|
|
{NULL, NULL, NULL}
|
|
};
|
|
|
|
static gib_classdesc_t Thread_class = {
|
|
"Thread", "Object",
|
|
Thread_Construct, NULL,
|
|
Thread_Destruct,
|
|
Thread_methods, Thread_class_methods
|
|
};
|
|
|
|
/*
|
|
Object Hash class
|
|
|
|
Stores references to objects in a Hash
|
|
*/
|
|
|
|
typedef struct ObjRef_s {
|
|
const char *key;
|
|
gib_object_t *obj;
|
|
} ObjRef_t;
|
|
|
|
typedef struct ObjectHash_s {
|
|
hashtab_t *objects;
|
|
} ObjectHash_t;
|
|
|
|
static const char *
|
|
ObjRef_Get_Key (void *ele, void *ptr)
|
|
{
|
|
return ((ObjRef_t *) ele)->key;
|
|
}
|
|
|
|
static void
|
|
ObjRef_Free (void *ele, void *ptr)
|
|
{
|
|
ObjRef_t *ref = ele;
|
|
free ((void *)ref->key);
|
|
GIB_Object_Decref (ref->obj);
|
|
free (ref);
|
|
}
|
|
|
|
static void *
|
|
ObjectHash_Construct (gib_object_t *obj)
|
|
{
|
|
ObjectHash_t *data = malloc (sizeof (ObjectHash_t));
|
|
|
|
data->objects = Hash_NewTable (1024, ObjRef_Get_Key, ObjRef_Free,
|
|
NULL);
|
|
|
|
return data;
|
|
}
|
|
|
|
static void
|
|
ObjectHash_Destruct (void *data)
|
|
{
|
|
ObjectHash_t *objh = data;
|
|
|
|
Hash_DelTable (objh->objects);
|
|
free (objh);
|
|
}
|
|
|
|
static int
|
|
ObjectHash_Insert_f (gib_object_t *obj, gib_method_t *method, void *data,
|
|
gib_object_t *sender, gib_message_t mesg)
|
|
{
|
|
ObjectHash_t *objh = data;
|
|
gib_object_t *ins;
|
|
ObjRef_t *new;
|
|
int i;
|
|
|
|
if (mesg.argc < 3)
|
|
return -1;
|
|
|
|
for (i = 2; i < mesg.argc; i++) {
|
|
if ((ins = GIB_Object_Get (mesg.argv[i]))) {
|
|
new = malloc (sizeof (ObjRef_t));
|
|
new->key = strdup (mesg.argv[1]);
|
|
new->obj = ins;
|
|
GIB_Object_Incref (ins);
|
|
Hash_Add (objh->objects, new);
|
|
} else
|
|
return -1;
|
|
}
|
|
|
|
GIB_Reply (obj, mesg, 0, NULL);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ObjectHash_Get_f (gib_object_t *obj, gib_method_t *method, void *data,
|
|
gib_object_t *sender, gib_message_t mesg)
|
|
{
|
|
ObjectHash_t *objh = data;
|
|
ObjRef_t **refs, **r;
|
|
const char **reply;
|
|
int i, len;
|
|
|
|
if (mesg.argc < 2)
|
|
return -1;
|
|
|
|
if ((refs = (ObjRef_t **) Hash_FindList (objh->objects,
|
|
mesg.argv[1]))) {
|
|
for (r = refs, len = 0; *r; r++, len++);
|
|
reply = malloc (sizeof (char **) * len);
|
|
for (r = refs, i = 0; *r; r++, i++)
|
|
reply[i] = (*r)->obj->handstr;
|
|
GIB_Reply (obj, mesg, len, reply);
|
|
free (reply);
|
|
} else
|
|
GIB_Reply (obj, mesg, 0, NULL);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
ObjectHash_Remove_f (gib_object_t *obj, gib_method_t *method, void *data,
|
|
gib_object_t *sender, gib_message_t mesg)
|
|
{
|
|
ObjectHash_t *objh = data;
|
|
ObjRef_t **refs, **r;
|
|
int i;
|
|
|
|
if (mesg.argc < 2)
|
|
return -1;
|
|
|
|
if ((refs = (ObjRef_t **) Hash_FindList (objh->objects,
|
|
mesg.argv[1]))) {
|
|
if (mesg.argc == 2)
|
|
for (r = refs; *r; r++) {
|
|
Hash_DelElement (objh->objects, *r);
|
|
Hash_Free (objh->objects, *r);
|
|
}
|
|
else
|
|
for (r = refs; *r; r++)
|
|
for (i = 2; i < mesg.argc; i++)
|
|
if (!strcmp (mesg.argv[i],
|
|
(*r)->obj->handstr))
|
|
{
|
|
Hash_DelElement
|
|
(objh->objects,
|
|
*r);
|
|
Hash_Free
|
|
(objh->objects,
|
|
*r);
|
|
}
|
|
}
|
|
GIB_Reply (obj, mesg, 0, NULL);
|
|
return 0;
|
|
}
|
|
|
|
static gib_methodtab_t ObjectHash_methods[] = {
|
|
{"insert", ObjectHash_Insert_f, NULL},
|
|
{"get", ObjectHash_Get_f, NULL},
|
|
{"remove", ObjectHash_Remove_f, NULL},
|
|
{NULL, NULL, NULL}
|
|
};
|
|
|
|
static gib_methodtab_t ObjectHash_class_methods[] = {
|
|
{NULL, NULL, NULL}
|
|
};
|
|
|
|
static gib_classdesc_t ObjectHash_class = {
|
|
"ObjectHash", "Object",
|
|
ObjectHash_Construct, NULL,
|
|
ObjectHash_Destruct,
|
|
ObjectHash_methods, ObjectHash_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;
|
|
|
|
if (!obj->vars)
|
|
obj->vars = GIB_Var_Hash_New ();
|
|
|
|
return NULL;
|
|
}
|
|
|
|
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.obj, GIB_DATA(thread)->reply.mesg, 0, NULL);
|
|
}
|
|
|
|
static int
|
|
Scrobj_Method_f (gib_object_t *obj, gib_method_t *method, void *data,
|
|
gib_object_t *sender, gib_message_t mesg)
|
|
{
|
|
static char this[] = "this";
|
|
static char send[] = "sender";
|
|
unsigned int ind;
|
|
cbuf_t *thread = GIB_Thread_New ();
|
|
static hashtab_t *nhash = NULL;
|
|
gib_var_t *var;
|
|
|
|
if (GIB_Function_Execute (thread, ((Scrobj_method_t *)method->data)->func,
|
|
mesg.argv, mesg.argc))
|
|
return -1;
|
|
|
|
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_DATA(thread)->globals = obj->vars;
|
|
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);
|
|
var = GIB_Var_Get_Complex (&GIB_DATA(thread)->locals, &nhash, send,
|
|
&ind, true);
|
|
if (sender)
|
|
dsprintf (var->array[0].value, "%lu", sender->handle);
|
|
else
|
|
dstring_copystr (var->array[0].value, "0");
|
|
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_tree_t *cur, *last;
|
|
gib_methodtab_t *new = malloc (sizeof
|
|
(gib_methodtab_t));
|
|
Scrobj_method_t *data = malloc (sizeof
|
|
(Scrobj_method_t));
|
|
for (last =
|
|
line->children->next->next;
|
|
last->next; last =
|
|
last->next);
|
|
data->func = GIB_Function_Define
|
|
(fname
|
|
(line->children->next->str),
|
|
last->str,
|
|
last->children,
|
|
script, NULL);
|
|
llist_flush (data->func->arglist);
|
|
data->func->minargs = 1;
|
|
for (cur = line->children->next->next;
|
|
cur != last; cur =
|
|
cur->next) {
|
|
llist_append
|
|
(data->func->arglist,
|
|
strdup (cur->str));
|
|
data->func->minargs++;
|
|
}
|
|
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);
|
|
GIB_Class_Create (&ObjectHash_class);
|
|
}
|