r26916@plastic: rob | 2007-07-02 08:16:37 +1000
[tangerine.git] / rom / oop / rootclass.c
blob341c61181e6e62eef8e35e2aa9c0ae0d7ab590c3
1 /*
2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: OOP rootclass
6 Lang: english
7 */
9 #include <proto/exec.h>
10 #include <proto/oop.h>
11 #include <proto/utility.h>
12 #include <exec/memory.h>
13 #include <oop/oop.h>
14 #include <string.h>
16 #include "intern.h"
17 #include "private.h"
19 #undef SDEBUG
20 #undef DEBUG
21 #define SDEBUG 0
22 #define DEBUG 0
23 #include <aros/debug.h>
25 #define MD(x) ((struct metadata *)x)
27 /***************************
28 ** RootClass' metaclass **
29 ***************************/
30 /* The root class' meta class is not really needed, but
31 it makes code of other metaclasses more consistent
34 #define OOPBase ((struct IntOOPBase *)(cl->OOPBasePtr))
35 #define IS_META_ATTR(attr, idx) ( (idx = attr - MetaAttrBase) < num_Meta_Attrs )
36 /**********************
37 ** BaseMeta::New() **
38 **********************/
39 static OOP_Object *basemeta_new(OOP_Class *cl, OOP_Object *o, struct pRoot_New *msg)
41 struct metadata *data;
43 struct OOP_InterfaceDescr *ifdescr = NULL;
44 STRPTR superid = NULL, clid = "-- private class -- ";
45 struct metadata *superptr = NULL;
46 struct TagItem *tag, *tstate;
47 ULONG instsize = (ULONG)-1L;
49 ULONG idx;
51 EnterFunc(bug("BaseMeta::New(cl=%s, msg = %p)\n",
52 cl->ClassNode.ln_Name, msg));
54 /* Analyze the taglist before object is allocated,
55 ** so we can easily exit cleanly if some info is missing
58 tstate = msg->attrList;
59 while ((tag = NextTagItem((const struct TagItem **)&tstate)))
61 if (IS_META_ATTR(tag->ti_Tag, idx))
63 D(bug("Got meta attr %lx with TagIdx %ld\n",
64 tag->ti_Tag, idx ));
66 switch (idx)
69 case aoMeta_SuperID:
70 /* ID of superclass */
71 superid = (STRPTR)tag->ti_Data;
72 D(bug("Got superID: %s\n", superid));
73 break;
75 case aoMeta_InterfaceDescr:
76 D(bug("Got ifdescr\n"));
77 /* What interfaces does the class support ? */
78 ifdescr = (struct OOP_InterfaceDescr *)tag->ti_Data;
79 break;
81 case aoMeta_ID:
82 /* The new class' ID */
83 clid = (STRPTR)tag->ti_Data;
84 D(bug("Got classID: %s\n", clid));
85 break;
87 case aoMeta_SuperPtr:
88 D(bug("Got superPtr\n"));
89 /* If the super class is private, than we must have
90 a pointer to it.
92 superptr = (struct metadata *)tag->ti_Data;
93 break;
95 case aoMeta_InstSize:
96 /* Instance data size for the new class */
97 instsize = (ULONG)tag->ti_Data;
98 break;
106 /* The user must supply instance size */
107 if (instsize == (ULONG)-1)
108 ReturnPtr ("Meta::New, no instsize", OOP_Object *, NULL);
110 /* The new class must have interfaces */
111 if (!ifdescr)
112 ReturnPtr ("Meta::New, no ifdescr", OOP_Object *, NULL);
114 /* The new class must have a superclass */
115 if (!superptr)
117 if (superid)
119 superptr = (struct metadata *)FindName((struct List *)&(GetOBase(OOPBase)->ob_ClassList), superid);
120 if (!superptr)
121 ReturnPtr ("Meta::New, no superptr/id", OOP_Object *, NULL);
125 /* We are sure we have enough args, and can let rootclass alloc the instance data */
126 o = (OOP_Object *)OOP_DoSuperMethod((OOP_Class *)cl, o, (OOP_Msg)msg);
127 if (o)
130 ULONG dispose_mid = OOP_GetMethodID(IID_Root, moRoot_Dispose);
132 D(bug("Instance allocated\n"));
134 data = OOP_INST_DATA(cl, o);
136 D(bug("o=%p,data=%p\n", o, data));
137 D(bug("instoffset: %ld\n", cl->InstOffset));
139 /* Clear instdata, so we in Dispose() can see what's been allocated */
140 memset(data, 0, sizeof (struct metadata));
142 D(bug("superptr=%p\n", superptr));
144 data->public.OOPBasePtr = (struct IntOOPBase *)OOPBase;
147 /* Let subclass create an initialize dispatch tables for the new class object*/
148 if (meta_allocdisptabs(o, (OOP_Class *)superptr, ifdescr))
150 data->disptabs_inited = TRUE;
152 /* Copy the class' ID */
153 D(bug("Allocating class ID\n"));
154 data->public.ClassNode.ln_Name = AllocVec(strlen (clid) + 1, MEMF_ANY);
155 if (data->public.ClassNode.ln_Name)
157 D(bug("class ID allocated\n"));
159 /* Initialize class fields */
160 D(bug("Setting instoffset\n"));
161 /* Instoffset */
162 if (superptr)
163 data->public.InstOffset = superptr->public.InstOffset + superptr->instsize;
164 else
165 data->public.InstOffset = 0UL;
166 D(bug("Setting other stuff\n"));
168 data->subclasscount = 0UL;
169 data->objectcount = 0UL;
170 data->superclass = (OOP_Class *)superptr;
171 data->instsize = instsize;
173 D(bug("Copying class ID\n"));
174 /* Copy class ID */
175 strcpy(data->public.ClassNode.ln_Name, clid);
178 ReturnPtr ("Meta::New", OOP_Object *, o);
182 OOP_CoerceMethod((OOP_Class *)cl, o, (OOP_Msg)&dispose_mid);
185 ReturnPtr ("Meta::New", OOP_Object *, NULL);
189 /**************************
190 ** BaseMeta::Dispose() **
191 **************************/
192 static VOID basemeta_dispose(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
194 struct metadata *data = OOP_INST_DATA(cl, o);
195 IPTR iterval = 0UL;
196 STRPTR interface_id = NULL;
197 ULONG num_methods = 0UL;
199 if (data->public.ClassNode.ln_Name)
200 FreeVec(data->public.ClassNode.ln_Name);
202 /* Release interfaces from global interface table */
203 while (meta_iterateifs(o, &iterval, &interface_id, &num_methods))
205 /* Only release the interfaces that were new for the class */
206 if (!meta_getifinfo((OOP_Object *)MD(o)->superclass, interface_id, &num_methods))
207 release_idbucket(interface_id, GetOBase(OOPBase));
211 if (data->disptabs_inited)
212 meta_freedisptabs(o);
214 OOP_DoSuperMethod(cl, o, msg);
216 return;
220 /****************************
221 ** BaseMeta::getifinfo() **
222 ****************************/
223 static struct IFMethod *basemeta_getifinfo(OOP_Class *cl, OOP_Object *o, struct P_meta_getifinfo *msg)
225 struct IFMethod *mtab = NULL;
226 EnterFunc(bug("BaseMeta::hasinterface(cl=%p, o=%p, iid=%s\n",
227 cl, o, msg->interface_id));
229 /* The object passed might be one of two classes: Root class or basemetaclass */
230 if (0 == strcmp(msg->interface_id, IID_Root))
232 /* Both classes support the root interface */
233 D(bug("Root interface\n"));
234 *(msg->num_methods_ptr) = num_Root_Methods;
235 if ( ((OOP_Class *)o) == BASEMETAPTR)
237 mtab = OOPBase->ob_BaseMetaObject.inst.rootif;
239 else
241 mtab = OOPBase->ob_RootClassObject.inst.rootif;
245 else if (0 == strcmp(msg->interface_id, IID_Meta))
247 D(bug("Meta interface. BASEMETAPTR: %p\n", BASEMETAPTR));
248 if ( ((OOP_Class *)o) == BASEMETAPTR )
251 /* Only BaseMeta has Meta interface */
252 mtab = OOPBase->ob_BaseMetaObject.inst.metaif;
253 *(msg->num_methods_ptr) = NUMTOTAL_M_Meta;
257 ReturnPtr ("BaseMeta::hasinterface", struct IFMethod *, mtab);
261 /*****************************
262 ** BaseMeta::iterateifs() **
263 *****************************/
264 static struct IFMethod *basemeta_iterateifs(
265 OOP_Class *cl, OOP_Object *o, struct P_meta_iterateifs *msg)
267 struct IFMethod *current_if = NULL;
269 EnterFunc(bug("BaseMeta::iterateifs(o=%p)\n", o));
271 /* As in has_interface() the object here can only be the basemetaclass, or rootclass */
272 if (((OOP_Class *)o) == ROOTCLASSPTR)
274 /* Rootclass have only one interface */
275 if ( *(msg->iterval_ptr) )
277 current_if = NULL;
279 else
281 current_if = OOPBase->ob_RootClassObject.inst.rootif;
282 *(msg->num_methods_ptr) = num_Root_Methods;
283 *(msg->interface_id_ptr) = IID_Root;
284 *(msg->iterval_ptr) = 1UL; /* We're through iterating */
287 else if (((OOP_Class *)o) == BASEMETAPTR)
289 struct basemeta_inst *inst = (struct basemeta_inst *)o;
290 switch (*(msg->iterval_ptr))
292 case 0:
293 current_if = inst->rootif;
294 *(msg->num_methods_ptr) = num_Root_Methods;
295 *(msg->interface_id_ptr) = IID_Root;
296 break;
298 case 1:
299 current_if = inst->metaif;
300 *(msg->num_methods_ptr) = NUMTOTAL_M_Meta;
301 *(msg->interface_id_ptr) = IID_Meta;
302 break;
304 default:
305 current_if = NULL;
306 break;
309 (*(msg->iterval_ptr)) ++;
312 else
314 /* Should never get here, unless someone has created an instance
315 of the BaseMeta class (which is meaningless)
317 current_if = NULL;
319 #if DEBUG
320 if (current_if)
322 D(bug("Current IF: %s, num_methods %ld\n",
323 *(msg->interface_id_ptr), *(msg->num_methods_ptr)));
325 #endif
326 ReturnPtr ("BaseMeta::iterate_ifs", struct IFMethod *, current_if);
330 #undef OOPBase
332 /*******************************
333 ** BaseMeta DoSuperMethod() **
334 *******************************/
335 /* cl->USerData passed to DoSuperMethodA might be
336 a subclass of rootclass, which does not have
337 the OOPBase in cl->UserData, so instead we use the
338 meta's UserData (IFMeta or HIDDMeta class
341 #define OOPBase ((struct IntOOPBase *)cl->OOPBasePtr)
343 static IPTR basemeta_dosupermethod(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
345 ULONG method_offset = *msg & METHOD_MASK;
346 struct IFMethod *ifm;
348 EnterFunc(bug("basemeta_dosupermethod(cl=%p, o=%p, msg=%p)\n",
349 cl, o, msg));
351 if (MD(cl)->superclass == ROOTCLASSPTR)
353 ifm = &(OOPBase->ob_RootClassObject.inst.rootif[*msg]);
355 else /* superclass is the BaseMeta class */
357 switch (*msg >> NUM_METHOD_BITS)
360 case 0:
361 ifm = &(OOPBase->ob_BaseMetaObject.inst.rootif[method_offset]);
362 break;
364 case 1:
365 ifm = &(OOPBase->ob_BaseMetaObject.inst.metaif[method_offset]);
366 break;
369 default:
370 D(bug("Error: basemeta_dosupermethod got method call to unknown interface %d\n",
371 *msg >> NUM_METHOD_BITS));
372 ifm = NULL;
373 break;
376 ReturnPtr ("basemeta_dosupermethod", IPTR, ifm->MethodFunc(ifm->mClass, o, msg));
379 #undef OOPBase
381 #define OOPBase ((struct IntOOPBase *)(cl->OOPBasePtr))
382 /*******************************
383 ** BaseMeta CoerceMethod() **
384 *******************************/
385 static IPTR basemeta_coercemethod(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
387 ULONG method_offset = *msg & METHOD_MASK;
388 struct IFMethod *ifm;
390 EnterFunc(bug("basemeta_coercemethod(cl=%p, o=%p, msg=%p)\n",
391 cl, o, msg));
394 switch (*msg >> NUM_METHOD_BITS)
397 case 0:
398 ifm = &(OOPBase->ob_BaseMetaObject.inst.rootif[method_offset]);
399 break;
401 case 1:
402 ifm = &(OOPBase->ob_BaseMetaObject.inst.metaif[method_offset]);
403 break;
406 default:
407 D(bug("Error: basemeta_coercemethod got method call to unknown interface %d\n",
408 *msg >> NUM_METHOD_BITS));
409 ifm = NULL;
410 break;
412 ReturnPtr ("basemeta_coercemethod", IPTR, ifm->MethodFunc(ifm->mClass, o, msg));
415 /************************
416 ** BaseMeta DoMethod **
417 ************************/
419 static IPTR basemeta_domethod(OOP_Object *o, OOP_Msg msg)
421 return basemeta_coercemethod(OOP_OCLASS(o), o, msg);
423 #undef OOPBase
425 /**********************
426 ** init_basemeta() **
427 **********************/
429 BOOL init_basemeta(struct IntOOPBase *OOPBase)
431 struct basemetaobject *bmo;
432 BOOL success;
433 ULONG mbase = NULL;
435 EnterFunc(bug("init_basemeta()\n"));
437 bmo = &(OOPBase->ob_BaseMetaObject);
438 bmo->oclass = BASEMETAPTR;
440 bmo->inst.data.public.ClassNode.ln_Name = "private base metaclass";
441 bmo->inst.data.public.OOPBasePtr = (struct Library *)OOPBase;
442 bmo->inst.data.public.InstOffset = 0UL;
443 bmo->inst.data.public.UserData = OOPBase;
444 bmo->inst.data.public.cl_DoSuperMethod = basemeta_dosupermethod;
445 bmo->inst.data.public.cl_CoerceMethod = basemeta_coercemethod;
446 bmo->inst.data.public.cl_DoMethod = basemeta_domethod;
448 bmo->inst.data.superclass = ROOTCLASSPTR;
449 bmo->inst.data.subclasscount = 0UL;
450 bmo->inst.data.objectcount = 0UL;
451 bmo->inst.data.instsize = sizeof (struct metadata);
452 bmo->inst.data.numinterfaces = NUM_BASEMETA_IFS;
454 /* Initialize interface table */
455 bmo->inst.iftable[0] = bmo->inst.rootif;
456 bmo->inst.iftable[1] = bmo->inst.metaif;
458 /* initialize interfaces */
459 bmo->inst.rootif[moRoot_New].MethodFunc = (IPTR (*)())basemeta_new;
460 bmo->inst.rootif[moRoot_Dispose].MethodFunc = (IPTR (*)())basemeta_dispose;
462 bmo->inst.rootif[moRoot_New].mClass = BASEMETAPTR;
463 bmo->inst.rootif[moRoot_Dispose].mClass = BASEMETAPTR;
465 /* Initialize meta interface */
466 bmo->inst.metaif[MO_meta_allocdisptabs].MethodFunc = (IPTR (*)())NULL;
467 bmo->inst.metaif[MO_meta_freedisptabs].MethodFunc = (IPTR (*)())NULL;
468 bmo->inst.metaif[MO_meta_getifinfo].MethodFunc = (IPTR (*)())basemeta_getifinfo;
469 bmo->inst.metaif[MO_meta_iterateifs].MethodFunc = (IPTR (*)())basemeta_iterateifs;
471 bmo->inst.metaif[MO_meta_allocdisptabs].mClass = BASEMETAPTR;
472 bmo->inst.metaif[MO_meta_freedisptabs].mClass = BASEMETAPTR;
473 bmo->inst.metaif[MO_meta_getifinfo].mClass = BASEMETAPTR;
474 bmo->inst.metaif[MO_meta_iterateifs].mClass = BASEMETAPTR;
476 /* Meta interface ID gets initialized to 1 */
477 success = init_mi_methodbase(IID_Meta, &mbase, OOPBase);
479 ReturnBool ("init_basemeta", success);
483 /* Root class is the base class of all classes.
484 (Well, one can create new baseclasses, but all classes must
485 implement the root interface).
488 /************************
489 ** Rootclass methods **
490 ************************/
492 /************
493 ** New() **
494 ************/
495 #define OOPBase ((struct IntOOPBase*)(root_cl->OOPBasePtr))
498 OOP_Object *root_new(OOP_Class *root_cl, OOP_Class *cl, struct pRoot_New *param)
500 struct _OOP_Object *o;
501 struct RootData *data;
503 EnterFunc(bug("Root::New(cl=%s, param = %p)\n",
504 cl->ClassNode.ln_Name, param));
506 /* Allocate memory for the object */
507 D(bug("Object size: %ld\n", MD(cl)->public.InstOffset + MD(cl)->instsize + sizeof (struct _OOP_Object)));
508 o = AllocVec(MD(cl)->public.InstOffset + MD(cl)->instsize + sizeof (struct _OOP_Object), MEMF_ANY|MEMF_CLEAR);
509 if (o)
511 D(bug("Mem allocated: %p\n", o));
512 o->o_Class = (OOP_Class *)cl;
514 data = (struct RootData *)OOP_BASEOBJECT(o);
516 /* Class has one more object */
517 MD(cl)->objectcount ++;
519 ReturnPtr ("Root::New", OOP_Object *, OOP_BASEOBJECT(o) );
522 ReturnPtr ("Root::New", OOP_Object *, NULL);
525 /****************
526 ** Dispose() **
527 ****************/
528 static VOID root_dispose(OOP_Class *root_cl, OOP_Object *o, OOP_Msg msg)
530 EnterFunc(bug("Root::Dispose(o=%p, oclass=%s)\n", o, _OOP_OBJECT(o)->o_Class->ClassNode.ln_Name));
532 MD(OOP_OCLASS(o))->objectcount --;
533 D(bug("Object mem: %p, size: %ld\n", _OOP_OBJECT(o), ((ULONG *)_OOP_OBJECT(o))[-1] ));
535 /* Free object's memory */
536 FreeVec(_OOP_OBJECT(o));
538 ReturnVoid("Root::Dispose");
541 static VOID root_get(OOP_Class *root_cl, OOP_Object *p, struct pRoot_Get *msg)
543 *msg->storage = 0UL;
544 D(bug("!!! Get() METHOD REACHED ROOTCLASS !!!\n"));
545 return;
548 #undef OOPBase
550 /**********************
551 ** init_rootclass() **
552 **********************/
553 BOOL init_rootclass(struct IntOOPBase *OOPBase)
556 struct rootclassobject *rco;
557 OOP_Class *rootclass;
559 BOOL success;
560 ULONG mbase = 0UL;
562 EnterFunc(bug("init_rootclass()\n"));
564 rco = &(OOPBase->ob_RootClassObject);
565 rootclass = &(rco->inst.data.public);
567 /* Its class is the metaobject */
568 rco->oclass = &(OOPBase->ob_BaseMetaObject.inst.data.public);
570 rco->inst.data.public.ClassNode.ln_Name = CLID_Root;
571 rco->inst.data.public.OOPBasePtr = (struct Library *)OOPBase;
572 rco->inst.data.public.InstOffset = NULL;
573 rco->inst.data.public.UserData = (APTR)OOPBase;
575 rco->inst.data.public.cl_DoMethod = NULL;
576 rco->inst.data.public.cl_CoerceMethod = NULL;
577 rco->inst.data.public.cl_DoSuperMethod = basemeta_dosupermethod;
578 rco->inst.data.public.cl_CoerceMethod = basemeta_coercemethod;
579 rco->inst.data.public.cl_DoMethod = basemeta_domethod;
581 D(bug("Root stuff: dosupermethod %p, coeremethod %p, domethod %p\n",
582 basemeta_dosupermethod, basemeta_coercemethod, basemeta_domethod));
584 rco->inst.data.superclass = NULL;
585 rco->inst.data.subclasscount = 0UL;
586 rco->inst.data.objectcount = 0UL;
587 rco->inst.data.instsize = 0UL;
588 rco->inst.data.numinterfaces = 1UL;
590 /* Initialize methodtable */
592 rco->inst.rootif[moRoot_New].MethodFunc = (IPTR (*)())root_new;
593 rco->inst.rootif[moRoot_New].mClass = rootclass;
595 rco->inst.rootif[moRoot_Dispose].MethodFunc = (IPTR (*)())root_dispose;
596 rco->inst.rootif[moRoot_Dispose].mClass = rootclass;
598 rco->inst.rootif[moRoot_Get].MethodFunc = (IPTR (*)())root_get;
599 rco->inst.rootif[moRoot_Get].mClass = rootclass;
601 /* Important: IID_Root interface ID MUST be the first one
602 initialized, so that it gets the value 0UL. This is
603 because it's used as rootclass both for IFMeta and HIDDMeta classes
606 success = init_mi_methodbase(IID_Root, &mbase, OOPBase);
607 if (success)
609 /* Make it public */
610 OOP_AddClass(rootclass);
613 ReturnBool ("init_rootclass", success);
616 /* Below is rootclass DoMethod and CoerceMethod. They are hardly useful,
617 cause you would never create an object of rootclass
621 #define ROOT_CALLMETHOD(cl, o, m) \
623 register struct IFMethod *ifm; \
624 ifm = &(RI(cl)->rootif[msg->MethodID]); \
625 return ifm->MethodFunc(ifm->mClass, o, msg); \
628 #define RI(cl) ((struct rootinst *)cl)
630 static IPTR root_domethod(OOP_Object *o, OOP_Msg msg)
632 register Class *cl;
633 cl = OCLASS(o);
635 ROOT_CALLMETHOD(cl, o, msg);
638 static IPTR root_coercemethod(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
640 ROOT_CALLMETHOD(cl, o, msg);