2 Copyright © 1995-2002, The AROS Development Team. All rights reserved.
8 /* Prevent inclusion of <intuition/classes.h>,
9 * which is referenced in the amiga inline macros
10 * imported below by <proto/exec.h>.
12 #define INTUITION_CLASSES_H
14 #include <proto/exec.h>
15 #include <exec/memory.h>
16 #include <exec/lists.h>
17 #include <exec/semaphores.h>
26 #include <aros/debug.h>
35 /**************** String class definitions ***********************/
37 /* Subclass of root */
38 #define CL_Level_String (CL_Level_Root + 1)
39 #define IF_Level_String (IF_Level_Root + 1)
41 #define STRINGCLASSNAME "stringclass"
43 /* Public New() parameter struct */
44 typedef struct NewStringParam
50 typedef struct StringInterface
52 VOID (*SetStr
)(Object
, STRPTR
);
53 VOID (*PrintStr
)(Object
);
56 typedef struct StringIFStorage
64 /* Private instance data definition */
71 /**************************************************/
74 Object
NewInstance(STRPTR classID
, APTR
, APTR
*interfaceStorage
);
75 Class
*CreateClass(STRPTR classID
, STRPTR superID
, struct MTabDescr
*mTabDescr
,
77 VOID
DeleteClass(STRPTR classID
);
80 /* could go into a library base */
81 struct SignalSemaphore ClassListSema
;
82 struct List ClassList
;
85 /*************************** String ***************************/
88 /* Method implementations */
90 Object
String_New(Class
*cl
, P_String
*p
)
94 /* Get parent interface */
95 IRoot
*ir
= (IRoot
*)CL_INTERFACE(cl
, CL_Level_Root
, IF_Level_Root
);
98 /* Whether it accepts NULL initparameter is class dependant.
99 ** The parameter could very well be a taglist
109 o
= ir
->New(cl
, NULL
);
114 /* Get instance data */
115 struct StringData
*data
= INST_DATA(o
, CL_Level_String
);
120 buffer
= AllocVec(max
+ 1, MEMF_ANY
);
124 strncpy(buffer
, str
, max
);
126 data
->Buffer
= buffer
;
127 data
->MaxStrLen
= max
;
133 /* Do a "CoerceMethod" (I get the Root interface from the *String* class) */
134 ir
= (IRoot
*)CL_INTERFACE(cl
, CL_Level_String
, IF_Level_Root
);
140 VOID
String_Dispose(Object o
)
142 struct StringData
*data
= INST_DATA(o
, CL_Level_String
);
144 IRoot
*ir
= (IRoot
*)OBJ_INTERFACE(o
, CL_Level_Root
, IF_Level_Root
);
149 FreeVec(data
->Buffer
);
152 ir
->Dispose(o
); /* Call supermethod */
157 VOID
String_SetStr(Object o
, STRPTR str
)
159 struct StringData
*data
= INST_DATA(o
, CL_Level_String
);
162 strncpy(data
->Buffer
, str
, data
->MaxStrLen
);
167 VOID
String_PrintStr(Object o
)
169 struct StringData
*data
;
171 data
= INST_DATA(o
, CL_Level_String
);
173 printf("%s", data
->Buffer
);
179 IRoot str_iroot
= { (Object (*)(Class
*, APTR
))String_New
, String_Dispose
};
181 IString str_istring
= {String_SetStr
, String_PrintStr
};
183 struct MTabDescr str_descr
[] =
185 {(APTR
*)&str_iroot
, 2}, /* Table contains two entries */
186 {(APTR
*)&str_istring
, 2} /* Table contains two entries */
190 int main(int argc
, char **argv
)
203 printf("Object system initialized\n");
205 /* Initialize the string class */
206 if (CreateClass(STRINGCLASSNAME
, ROOTCLASSNAME
, str_descr
, sizeof (struct StringData
)) )
209 P_String pstr
= {"String test", 80};
211 printf("Class list:\n");
212 ForeachNode(&ClassList
, n
)
214 printf("%s\n", n
->ln_Name
);
218 /* Create a new instance */
219 o
= NewInstance(STRINGCLASSNAME
, &pstr
, (APTR
*)&st
);
222 IString
*is
= st
.IString
;
224 printf("New instance: %p\n", o
);
226 printf("Current string: ");
230 printf("Setting string\n");
231 is
->SetStr(o
, "Blah");
233 printf("New string value: ");
237 st
.IRoot
->Dispose(o
);
239 printf("object deleted\n");
241 DeleteClass(STRINGCLASSNAME
);
254 /******************************************************************/
256 /* The oop system code */
258 BOOL
AllocInterfaces(Class
*cl
);
259 VOID
FreeInterfaces(Class
*cl
);
267 Class
*CreateClass(STRPTR classID
, STRPTR superID
, struct MTabDescr
*mTabDescr
,
270 #define UB(x) ((UBYTE *)x)
272 #define UnlockCL ReleaseSemaphore( &ClassListSema )
273 #define LockCLShared ObtainSemaphoreShared( &ClassListSema )
274 #define LockCL ObtainSemaphore( &ClassListSema )
276 #define ClassID ClassNode.ln_Name
281 /* Find superclass */
282 EnterFunc(bug("CreateClass(classID=%s, superID=%s, mTabDescr=%p, instDataSize=%d)\n",
283 classID
, superID
, mTabDescr
, instDataSize
));
286 supercl
= (Class
*)FindName( &ClassList
, superID
);
289 /* Mark the class as busy, so it isn't freed while we are allocating
290 ** stuff for our class
292 supercl
->SubClassCount
++;
299 D(bug("Found superclass %s\n", supercl
->ClassID
));
301 /* Allocate class structure */
302 D(bug("Allocating class of size %d\n", sizeof (Class
) ));
303 cl
= AllocMem(sizeof (Class
), MEMF_PUBLIC
|MEMF_CLEAR
); /* Can be made read-only for MP */
306 ULONG cltab_size
, iftab_size
;
310 D(bug("Allocated class structure\n"));
312 /* Find this class's level in the hierarchy */
314 /* How many super-classes are there ? */
315 super_count
= 1; /* have allready found one superclass */
316 for (superptr
= supercl
; superptr
->SuperClass
; superptr
= superptr
->SuperClass
)
319 D(bug("Number of superclasses: %d\n", super_count
));
321 /* Get size of interface table */
322 iftab_size
= UB(&(cl
->InterfaceTable
[super_count
+ 1])) - UB(&(cl
->InterfaceTable
[0]));
323 D(bug("IF tabsize: %d\n", iftab_size
));
325 /* Allocate interface table pointers */
326 cl
->InterfaceTable
= AllocMem(iftab_size
, MEMF_PUBLIC
|MEMF_CLEAR
); /* Can be made read-only for MP */
328 /* Get size of class table */
329 cltab_size
= UB( &(cl
->ClassTable
[super_count
+ 1])) - UB( &(cl
->ClassTable
[0]));
330 D(bug("CL tabsize: %d\n", cltab_size
));
332 /* Allocate interface methodtable pointers */
333 cl
->ClassTable
= AllocMem(cltab_size
, MEMF_PUBLIC
|MEMF_CLEAR
); /* Can be made read-only for MP */
334 D(bug("Classtable allocated: %p\n"));
336 cl
->ClassID
= AllocVec( strlen(classID
) + 1, MEMF_PUBLIC
);
338 if (cl
->InterfaceTable
&& cl
->ClassTable
&& cl
->ClassID
)
341 D(bug("Tables allocated\n"));
343 strcpy(cl
->ClassID
, classID
);
344 D(bug("class ID copied\n"));
346 /* !!! Important to fill in these before calling AllocInterfaces */
347 cl
->NumMethods
= mTabDescr
[super_count
].NumMethods
;
348 cl
->SuperClass
= supercl
;
350 D(bug("Number of methods introduced by class: %d\n", cl
->NumMethods
));
352 /* Allocate interfaces for class */
353 if (AllocInterfaces(cl
))
358 Class
*superptr
= supercl
;
361 /* Fill in the interfaces from the superclass */
362 for (idx
= super_count
- 1; idx
>= 0; idx
-- )
364 D(bug("Getting interface %d with %d methods from class %s\n",
365 idx
, superptr
->NumMethods
, superptr
->ClassID
));
367 CopyMem( superptr
->InterfaceTable
[idx
],
368 cl
->InterfaceTable
[idx
],
369 UB( &ifptr
[superptr
->NumMethods
]) - UB( &ifptr
[0]) );
371 /* And fill in the class table while we're at it */
372 cl
->ClassTable
[idx
] = superptr
;
373 superptr
= superptr
->SuperClass
;
377 /* Fill in ourselves in the classtable */
378 cl
->ClassTable
[super_count
] = cl
;
380 /* Override the interfaces with our own methods */
381 for (idx
= super_count
- 1; idx
>= 0; idx
-- )
383 mtab
= mTabDescr
[idx
].Table
;
384 iftab
= cl
->InterfaceTable
[idx
];
386 for (m_idx
= mTabDescr
[idx
].NumMethods
- 1; m_idx
>= 0; m_idx
-- )
388 if (mtab
[m_idx
] != NULL
)
390 D(bug("Overriding method at cl_idx=%d, method=%d\n", idx
, m_idx
));
391 D(bug("Method overrided: %p, overrider: %p\n", iftab
[m_idx
], mtab
[m_idx
]));
392 /* Override method */
393 iftab
[m_idx
] = (IPTR
)mtab
[m_idx
];
396 } /* For each method in the method table */
398 } /* For each level above us in the hierarchy */
400 /* Fill in the methods that are new with this class */
401 D(bug("Filling in methods at level %d\n", super_count
));
402 CopyMem(mTabDescr
[super_count
].Table
,
403 cl
->InterfaceTable
[super_count
],
404 UB( &ifptr
[ mTabDescr
[super_count
].NumMethods
]) - UB( &ifptr
[0]) );
407 /* Update instance data info */
408 cl
->InstOffset
= supercl
->InstOffset
+ supercl
->InstSize
;
409 cl
->InstSize
= instDataSize
;
411 cl
->SuperCount
= super_count
;
414 AddTail(&ClassList
, &(cl
->ClassNode
) );
417 ReturnPtr ("CreateClass", Class
*, cl
);
421 if (cl
->InterfaceTable
)
422 FreeMem(cl
->InterfaceTable
, iftab_size
);
425 FreeMem(cl
->ClassTable
, cltab_size
);
428 FreeVec(cl
->ClassID
);
432 FreeMem(cl
, sizeof (struct IClass
));
436 /* Initalization failed, free lock on superclass */
437 supercl
->SubClassCount
--;
439 ReturnPtr ("CreateClass", Class
*, NULL
);
445 /************************
446 ** AllocInterfaces() **
447 ************************/
448 BOOL
AllocInterfaces(Class
*param_cl
)
450 IPTR
**ifptr
= param_cl
->InterfaceTable
;
453 EnterFunc(bug("AllocInterfaces(cl=%s)\n", param_cl
->ClassID
));
455 /* Allocate the interfaces */
456 for ( cl
= param_cl
; cl
; cl
= cl
->SuperClass
)
458 ULONG size
= UB( &((*ifptr
)[cl
->NumMethods
])) - UB( &((*ifptr
)[0]));
460 D(bug("Allocating interface for class %s, size=%d\n", cl
->ClassID
, size
));
461 *ifptr
= AllocMem(size
, MEMF_PUBLIC
|MEMF_CLEAR
); /* Should be read-only for MP */
462 D(bug("IF Allocated: %p\n", *ifptr
));
465 FreeInterfaces(param_cl
);
466 ReturnBool ("AllocInterfaces", FALSE
);
472 ReturnBool ("AllocInterfaces", TRUE
);
475 /***********************
476 ** FreeInterfaces() **
477 ***********************/
478 VOID
FreeInterfaces(Class
*cl
)
480 IPTR
**ifptr
= cl
->InterfaceTable
;
482 EnterFunc(bug("FreeInterfaces(cl=%s)\n", cl
->ClassID
));
484 for ( ; cl
; cl
= cl
->SuperClass
)
488 ULONG size
= UB( &(*ifptr
)[cl
->NumMethods
]) - UB(&(*ifptr
)[0]);
490 D(bug("Freeing IF %p of size %d\n", *ifptr
, size
));
491 FreeMem(*ifptr
, size
);
496 ReturnVoid ("FreeInterfaces");
505 VOID
DeleteClass(STRPTR classID
)
509 EnterFunc(bug("DeleteClass(classID=%s)\n", classID
));
512 cl
= (Class
*)FindName( &ClassList
, classID
);
518 ULONG tab_entries
= cl
->SuperCount
+ 1;
521 /* What level are we ? */
522 if (cl
->SuperCount
== 0) /* Someone trying to remove the rootclass */
523 ReturnVoid("DeleteClass (Someone trying to remove rootclass)");
525 /* Free interfaces */
528 size
= UB(&cl
->InterfaceTable
[tab_entries
]) - UB(&cl
->InterfaceTable
[0]);
529 D(bug("Freeing IFTab of size %d\n", size
));
530 FreeMem(cl
->InterfaceTable
, size
);
532 size
= UB(&cl
->ClassTable
[tab_entries
]) - UB(&cl
->ClassTable
[0]);
533 D(bug("Freeing ClassTab of size %d at %p\n", size
, cl
->ClassTable
));
534 FreeMem(cl
->ClassTable
, size
);
537 D(bug("Freeing class ID %s\n", cl
->ClassID
));
538 FreeVec(cl
->ClassID
);
540 Remove(&(cl
->ClassNode
));
543 FreeMem(cl
, sizeof (Class
));
545 ReturnVoid("DeleteClass");
548 /************************
549 ** Rootclass methods **
550 ************************/
556 #define NUMROOTMETHODS 2
558 Object
Root_New(Class
*cl
, APTR param
)
562 EnterFunc(bug("Root::New(cl=%s, param = %p)\n",
563 cl
->ClassNode
.ln_Name
, param
));
565 /* Allocate memory for the object */
566 D(bug("Object size: %d\n", cl
->InstOffset
+ cl
->InstSize
+ sizeof (struct _Object
)));
567 o
= AllocVec(cl
->InstOffset
+ cl
->InstSize
+ sizeof (struct _Object
), MEMF_ANY
);
570 D(bug("Mem allocated: %p\n", o
));
575 ReturnPtr ("Root::New", Object
, BASEOBJECT(o
) );
578 ReturnPtr ("Root::New", Object
, NULL
);
581 VOID
Root_Dispose(Object o
)
583 EnterFunc(bug("Root::Dispose(o=%p, oclass=%s)\n", o
, _OBJECT(o
)->Class
->ClassNode
.ln_Name
));
585 _OBJECT(o
)->Class
->ObjectCount
--;
586 D(bug("Object mem: %p, size: %d\n", _OBJECT(o
), ((ULONG
*)_OBJECT(o
))[-1] ));
589 ReturnVoid("Root::Dispose");
600 Class
*RootClass
= &RootClassMem
;
602 InitSemaphore(&ClassListSema
);
605 /* We must initialize the rootclass by hand */
607 /* Class table. Only needs place for myself */
608 RootClass
->ClassTable
= (struct IClass
**)AllocMem( sizeof(Class
*), MEMF_PUBLIC
);
609 if (RootClass
->ClassTable
)
612 /* Interface table. Only needs place for our own interface */
613 RootClass
->InterfaceTable
= (IPTR
**)AllocMem( sizeof (IPTR
*), MEMF_PUBLIC
);
614 if (RootClass
->InterfaceTable
)
619 /* Allocate interface */
620 if_size
= UB(&interface
[NUMROOTMETHODS
]) - UB(&interface
[0]);
621 interface
= AllocMem(if_size
, MEMF_PUBLIC
);
624 /* Fill in methods */
625 interface
[0] = (IPTR
)Root_New
;
626 interface
[1] = (IPTR
)Root_Dispose
;
628 RootClass
->InterfaceTable
[0] = interface
;
630 /* Fill in other stuff into the class structure */
631 RootClass
->ClassNode
.ln_Name
= ROOTCLASSNAME
;
632 RootClass
->ClassTable
[0] = RootClass
;
633 RootClass
->InstOffset
= 0UL;
634 RootClass
->InstSize
= sizeof (struct RootData
);
635 RootClass
->NumMethods
= NUMROOTMETHODS
;
636 RootClass
->SubClassCount
= 0UL;
637 RootClass
->ObjectCount
= 0UL;
638 RootClass
->SuperClass
= NULL
;
639 RootClass
->SuperCount
= 0UL;
641 /* Add the class. Arbitration not necessary, as
642 ** noone know about us yet
644 AddTail(&ClassList
, &(RootClass
->ClassNode
) );
649 FreeMem(RootClass
->InterfaceTable
, sizeof (IPTR
**));
651 FreeMem(RootClass
->ClassTable
, sizeof (Class
*));
667 Class
*RootClass
= &RootClassMem
;
669 FreeMem(RootClass
->ClassTable
, sizeof (APTR
*));
671 interface
= RootClass
->InterfaceTable
[0];
672 if_size
= UB(&interface
[NUMROOTMETHODS
]) - UB(&interface
[0]);
674 FreeMem(interface
, if_size
);
676 FreeMem(RootClass
->InterfaceTable
, sizeof (IPTR
**));
684 Object
NewInstance(STRPTR classID
, APTR param
, APTR
*interfaceStorage
)
691 EnterFunc(bug("NewInstance(classID=%s, param=%p, ifStorage=%p)\n",
692 classID
, param
, interfaceStorage
));
695 cl
= (Class
*)FindName(&ClassList
, classID
);
697 cl
->ObjectCount
++; /* We don't want the class to be freed while we work on it */
703 /* Get interfaces from class */
705 for ( idx
= cl
->SuperCount
; idx
>= 0; idx
-- )
706 interfaceStorage
[idx
] = cl
->InterfaceTable
[idx
];
708 /* Create a new instance */
709 D(bug("Calling New() at %p\n", ((IRoot
*) interfaceStorage
[cl
->SuperCount
])->New
));
710 o
= ((IRoot
*) interfaceStorage
[0])->New(cl
, param
);
715 cl
->ObjectCount
--; /* Object creation failed, release lock */
718 ReturnPtr ("NewInstance", Object
, o
);