Merging in v11.21
[AROS.git] / workbench / classes / zune / betterstring / include / mccinit.c
blobf04e38fc23ff6377b2f97cf2e5ea4859ef99ef97
1 /*******************************************************************************
3 Name: mccinit.c
4 Versionstring: $VER: mccinit.c 1.24 (05.10.2010)
5 Author: Jens Langner <Jens.Langner@light-speed.de>
6 Distribution: PD (public domain)
7 Description: library init file for easy generation of a MUI
8 custom classes (MCC/MCP)
9 History:
11 1.0 09.06.2007 : created based on obsolete mccheader.c (damato)
12 1.1 10.06.2007 : modified LibInit/LibOpen/LibExpunge to call the actual
13 ClassOpen() in LibOpen() rather than in LibInit(). This
14 should prevent stack issues common on e.g. OS3. (damato)
15 1.2 01.07.2007 : adapted library interface initialization to what the
16 very latest idltool 52.7 produces as well.
17 1.3 04.07.2007 : added MIN_STACKSIZE and all required StackSwap()
18 mechanisms to enforce a large enough stack.
19 1.4 04.07.2007 : put the StackSwapStruct structure on the stack to avoid
20 crashes on OS3/MOS.
21 1.5 18.07.2007 : added new inline assember stackswap_call() function which
22 allows to call a function within a new stack frame
23 initiated by StackSwap(). This should make the whole
24 stack swapping mechanism more safe.
25 1.6 24.07.2007 : corrected an else-branch which only exists if CLASSINIT
26 is defined and added an UNUSED extension to the Expunge()
27 function in case the base parameter is not used.
28 1.7 25.07.2007 : adapted GETINTERFACE() and library base definitions so
29 that mccinit.c can also be used with C++
30 1.8 25.07.2007 : removed the obsolete 2-parameter version of GETINTERFACE()
31 from mcc_common.h and adapted all calls accordingly.
32 Also moved the inclusion of mccinit.c in front of all
33 user definable functions.
34 1.9 09.08.2007 : applied a patch kindly provided by Ilkka Lehtoranta which
35 replaces the assembler code for stack swapping with the
36 appropriate call to the NewPPCStackSwap() function in
37 MorphOS. In addition, the stack size will now be properly
38 checked before a stack swap is attempted.
39 1.10 13.08.2007 : the StackSwap structure itself *must* *not* be placed on the
40 stack which will be swapped later, because swapping it back
41 will access the wrong place in memory. Hence this structure
42 is allocated from global memory now.
43 1.11 01.02.2008 : fixed some minor compiler warnings when compiled using the
44 MorphOS SDK.
45 1.12 27.03.2009 : integrated some changes which should make mccinit usable
46 for AROS builds.
47 1.13 01.04.2009 : fixed the broken prototype for the assembler stackswap_call
48 function.
49 1.14 02.05.2009 : added RTF_EXTENDED for the MorphOS build as well
50 1.15 24.05.2009 : fixed some compiler warnings appear on AROS compile
51 1.16 25.05.2009 : fixed some compiler warnings appear on OS3/MOS compile
52 1.17 02.06.2009 : more fixes to better comply for AROS compilation
53 1.18 24.04.2010 : fixed stack swapping for AROS
54 1.19 25.05.2010 : updated for compatibility with AROS V1 API
55 1.20 01.06.2010 : added CleanupDebug() call to expunge function.
56 1.21 17.08.2010 : the UserLibName and UserLibID strings are now correctly
57 placed in the .data instead of the .text section. Also made
58 sure that the _start() function is really the first entry,
59 otherwise random data will be executed as code, which will
60 crash for sure.
61 1.22 03.09.2010 : the library semaphore is now correctly cleared ahead of the
62 InitSemaphore() call.
63 1.23 07.09.2010 : added missing #include <string.h> for memset().
64 1.24 05.10.2010 : make sure that removing the library during LibClose() really
65 operates on the correct base. Calling LibExpunge() on MorphOS
66 is wrong, since that takes no parameter but expects the base
67 to be in A6. We work around this by using an additional
68 function which gets called from LibClose() and LibExpunge()
69 with the correct base pointer.
71 About:
73 The purpose of this source file is to provide a template for the library init
74 code for a creation of an own MUI custom class (mcc/mcp) for AmigaOS4,
75 AmigaOS3 and MorphOS. By directly including this file (#include "mccinit.c")
76 and defining certain preprocessor values, a MUI developer doesn't have to
77 care about library init stuff which is normally highly system dependent and
78 various between different Amiga operating systems.
80 Usage:
82 This file should be included by another source file (e.g. 'library.c') in
83 your main development branch while certain preprocessor macros right before
84 the include statement can be defined to change the behaviour of mccinit.c.
85 These possible macros are:
87 USERLIBID (char*) - version string for the mcc/mcp (exluding $VER:)
88 VERSION (int) - version number (must match USERLIBID)
89 REVISION (int) - revision number (must match USERLIBID)
90 CLASS (char*) - class name (including .mcc/.mcp)
91 MASTERVERSION (int) - the minimun required muimaster version
92 (default: MUIMASTER_VMIN)
93 MIN_STACKSIZE (int) - if defined, the specified minimum stack size
94 will be enforced when calling all user functions
95 like ClassXXXX() and PreClassXXX().
97 MCC only:
98 --------
99 SUPERCLASS (char*) - superclass ID of MCC (e.g. MUIC_Area)
100 INSTDATA - name of instance data structure of MCC (e.g. InstData)
101 USEDCLASSES - name of NULL terminated string array which contains
102 names of other required custom classes for MCC.
103 _Dispatcher - name of Dispatcher function for MCC
105 MCP only:
106 -------
107 SUPERCLASSP (char*) - superclass ID of MCP (e.g. MUIC_Mccprefs)
108 INSTDATAP - name of instance data structure of MCP
109 USEDCLASSESP - name of NULL terminated string array which contains
110 names of other required custom classes for MCC.
111 SHORTHELP (char*) - alternative help text for prefs program's listview
112 PREFSIMAGEOBJECT - pointer to the image object for the MCP
113 _DispatcherP - name of Dispatcher function for MCP
115 In addition, the following defines and functions can be defined or are
116 required:
118 CLASSINIT - if defined, a "BOOL ClassInit(struct Library *base)"
119 function can be defined in your own code and will be called
120 right after the general library initialization are
121 finished. This function should then open own libraries
122 or do own library initialization tasks as it is only called
123 once at the very first library/class open.
125 CLASSEXPUNGE - if defined a "VOID ClassExpunge(struct Library *base)"
126 function can be defined in your own code and will be called
127 as soon as the library will be freed/expunged by the
128 operating system. In this function you should close/free
129 stuff you normally opened/allocated in CLASSINIT.
131 CLASSOPEN - if defined, a "BOOL ClassOpen(struct Library *base)"
132 function can be defined in your own code and will be called
133 right after each single application opens the custom class.
134 In this function you can then set flags or do library open
135 specific tasks.
137 CLASSCLOSE - if defined a "VOID ClassClose(struct Library *base)"
138 function can be defined in your own code and will be called
139 right after the library was successfully flagged as closed
140 by the CloseLibrary() call of an application.
143 PRECLASSINIT - if defined a "BOOL PreClassInit(struct Library *base)"
144 function can be defined and will be called right _before_
145 and library initialization takes place.
147 POSTCLASSEXPUNGE - if defined a "BOOL PostClassExpunge(struct Library *base)"
148 function can be defined and will be called right _after_
149 the custom class was free via MUI_DeleteCustomClass() in
150 the library expunge phase.
152 Warning:
153 -------
154 The above class functions are normally called by the operating system
155 in a Forbid()/Permit() state. That means you are supposed to make sure that
156 your operations doesn't break the Forbid() state or otherwise you may run
157 into a race condition. However, we have added semaphore locking to partly
158 protect you from that case - but you should still consider doing processor
159 intensitive tasks in a library's own function instead of using those
160 class initialization functions.
162 *******************************************************************************/
164 /******************************************************************************/
165 /* Includes */
166 /******************************************************************************/
168 #include <string.h>
170 #ifdef __MORPHOS__
171 #include <emul/emulinterface.h>
172 #include <emul/emulregs.h>
173 #endif
175 #include <exec/types.h>
176 #include <exec/memory.h>
177 #include <exec/libraries.h>
178 #include <exec/semaphores.h>
179 #include <exec/resident.h>
180 #include <exec/execbase.h>
181 #include <dos/dos.h>
183 #include <proto/exec.h>
184 #include <proto/muimaster.h>
185 #include <proto/utility.h>
186 #include <proto/dos.h>
187 #include <proto/graphics.h>
188 #include <proto/intuition.h>
190 #ifdef __AROS__
191 #include <aros/libcall.h>
192 #include <utility/utility.h>
193 #endif
195 #include <SDI/SDI_compiler.h>
197 #if defined(__amigaos4__)
198 struct Library *MUIMasterBase = NULL;
199 struct Library *SysBase = NULL;
200 struct Library *UtilityBase = NULL;
201 struct Library *DOSBase = NULL;
202 struct Library *GfxBase = NULL;
203 struct Library *IntuitionBase = NULL;
204 struct ExecIFace *IExec = NULL;
205 struct MUIMasterIFace *IMUIMaster = NULL;
206 struct UtilityIFace *IUtility = NULL;
207 struct DOSIFace *IDOS = NULL;
208 struct GraphicsIFace *IGraphics = NULL;
209 struct IntuitionIFace *IIntuition = NULL;
210 #if defined(__NEWLIB__)
211 struct Library *NewlibBase = NULL;
212 struct Interface *INewlib = NULL;
213 #endif
214 #else
215 struct Library *MUIMasterBase = NULL;
216 struct ExecBase *SysBase = NULL;
217 #if defined(__AROS__)
218 struct UtilityBase *UtilityBase = NULL;
219 #else
220 struct Library *UtilityBase = NULL;
221 #endif
222 struct DosLibrary *DOSBase = NULL;
223 struct GfxBase *GfxBase = NULL;
224 struct IntuitionBase *IntuitionBase = NULL;
225 #endif
227 #ifdef __cplusplus
228 extern "C" {
229 #endif
231 // we place a stack cookie in the binary so that
232 // newer OS version can directly take the specified
233 // number for the ramlib process
234 #if defined(MIN_STACKSIZE)
236 // transforms a define into a string
237 #define STR(x) STR2(x)
238 #define STR2(x) #x
240 #ifdef __amigaos4__
241 STATIC const char USED_VAR stack_size[] = "$STACK:" STR(MIN_STACKSIZE) "\n";
242 #endif
243 #endif
245 /* The name of the class will also become the name of the library. */
246 /* We need a pointer to this string in our ROMTag (see below). */
247 STATIC const char UserLibName[] = CLASS;
248 STATIC const char UserLibID[] = "$VER: " USERLIBID;
250 #ifdef SUPERCLASS
251 STATIC struct MUI_CustomClass *ThisClass = NULL;
252 DISPATCHERPROTO(_Dispatcher);
253 #endif
255 #ifdef SUPERCLASSP
256 STATIC struct MUI_CustomClass *ThisClassP = NULL;
257 DISPATCHERPROTO(_DispatcherP);
258 #endif
260 #ifdef __GNUC__
262 #if !defined(__NEWLIB__)
263 #if defined(__amigaos4__)
264 extern struct Library *__UtilityBase; // clib2
265 extern struct UtilityIFace* __IUtility; // clib2
266 #else
267 struct Library *__UtilityBase = NULL; // required by libnix & clib2
268 #endif
269 #endif
271 /* these one are needed copies for libnix.a */
272 #ifdef __libnix__
273 #ifdef USE_MATHIEEEDOUBBASBASE
274 struct Library *__MathIeeeDoubBasBase = NULL;
275 #endif
276 #ifdef USE_MATHIEEEDOUBTRANSBASE
277 struct Library *__MathIeeeDoubTransBase = NULL;
278 #endif
279 #endif
281 #endif /* __GNUC__ */
284 // define own macros for the OS4 interfaces
285 #undef GETINTERFACE
286 #undef DROPINTERFACE
287 #if defined(__amigaos4__)
288 #define GETINTERFACE(iface, type, base) (iface = (type)GetInterface((struct Library *)(base), "main", 1L, NULL))
289 #define DROPINTERFACE(iface) (DropInterface((struct Interface *)iface), iface = NULL)
290 #else
291 #define GETINTERFACE(iface, type, base) TRUE
292 #define DROPINTERFACE(iface)
293 #endif
295 // in case the user didn't specify an own minimum
296 // muimaster version we increase it here.
297 #ifndef MASTERVERSION
298 #define MASTERVERSION MUIMASTER_VMIN
299 #endif
301 /* Our library structure, consisting of a struct Library, a segment pointer */
302 /* and a semaphore. We need the semaphore to protect init/exit stuff in our */
303 /* open/close fuSnctions */
304 struct LibraryHeader
306 struct Library lh_Library;
307 UWORD lh_Pad1;
308 BPTR lh_Segment;
309 struct SignalSemaphore lh_Semaphore;
310 UWORD lh_Pad2;
313 /******************************************************************************/
314 /* Local Structures & Prototypes */
315 /******************************************************************************/
317 #if defined(__amigaos4__)
319 STATIC struct LibraryHeader * LIBFUNC LibInit (struct LibraryHeader *base, BPTR librarySegment, struct ExecIFace *pIExec);
320 STATIC BPTR LIBFUNC LibExpunge (struct LibraryManagerInterface *Self);
321 STATIC struct LibraryHeader * LIBFUNC LibOpen (struct LibraryManagerInterface *Self, ULONG version);
322 STATIC BPTR LIBFUNC LibClose (struct LibraryManagerInterface *Self);
323 STATIC IPTR LIBFUNC MCC_Query (UNUSED struct Interface *self, REG(d0, LONG which));
325 #elif defined(__MORPHOS__)
327 STATIC struct LibraryHeader * LIBFUNC LibInit (struct LibraryHeader *base, BPTR librarySegment, struct ExecBase *sb);
328 STATIC BPTR LIBFUNC LibExpunge (void);
329 STATIC struct LibraryHeader * LIBFUNC LibOpen (void);
330 STATIC BPTR LIBFUNC LibClose (void);
331 STATIC LONG LIBFUNC LibNull (void);
332 STATIC IPTR LIBFUNC MCC_Query (void);
334 #elif defined(__AROS__)
336 AROS_UFP3 (struct LibraryHeader *, LibInit,
337 AROS_UFPA(struct LibraryHeader *, base, D0),
338 AROS_UFPA(BPTR, librarySegment, A0),
339 AROS_UFPA(struct ExecBase *, sb, A6)
341 AROS_LD1(BPTR, LibExpunge,
342 AROS_LPA(struct LibraryHeader *, base, D0),
343 struct LibraryHeader *, base, 3, __MCC_
345 AROS_LD1 (struct LibraryHeader *, LibOpen,
346 AROS_LHA (ULONG, version, D0),
347 struct LibraryHeader *, base, 1, __MCC_
349 AROS_LD0 (BPTR, LibClose,
350 struct LibraryHeader *, base, 2, __MCC_
352 AROS_LD1(IPTR, MCC_Query,
353 AROS_LHA(LONG, what, D0),
354 struct LibraryHeader *, LIBBASE, 5, __MCC_
357 #else
359 STATIC struct LibraryHeader * LIBFUNC LibInit (REG(d0, struct LibraryHeader *base), REG(a0, BPTR librarySegment), REG(a6, struct ExecBase *sb));
360 STATIC BPTR LIBFUNC LibExpunge (REG(a6, struct LibraryHeader *base));
361 STATIC struct LibraryHeader * LIBFUNC LibOpen (REG(d0, ULONG version), REG(a6, struct LibraryHeader *base));
362 STATIC BPTR LIBFUNC LibClose (REG(a6, struct LibraryHeader *base));
363 STATIC LONG LIBFUNC LibNull (void);
364 STATIC IPTR LIBFUNC MCC_Query (REG(d0, LONG which));
366 #endif
368 /******************************************************************************/
369 /* Dummy entry point and LibNull() function all in one */
370 /******************************************************************************/
373 * The system (and compiler) rely on a symbol named _start which marks
374 * the beginning of execution of an ELF file. To prevent others from
375 * executing this library, and to keep the compiler/linker happy, we
376 * define an empty _start symbol here.
378 * On the classic system (pre-AmigaOS4) this was usually done by
379 * moveq #0,d0
380 * rts
384 #if defined(__amigaos4__) && !defined(__AROS__) && !defined(__MORPHOS__)
385 #if !defined(__mc68000__)
386 int32 _start(void)
388 return RETURN_FAIL;
390 #else
391 asm(".text \n\
392 .even \n\
393 .globl _start \n\
394 _start: \n\
395 moveq #0,d0 \n\
396 rts");
397 #endif
398 #endif
400 #if !defined(__amigaos4__)
401 STATIC LONG LIBFUNC LibNull(VOID)
403 return(0);
405 #endif
407 /******************************************************************************/
408 /* Local data structures */
409 /******************************************************************************/
411 #if defined(__amigaos4__)
412 /* ------------------- OS4 Manager Interface ------------------------ */
413 STATIC uint32 _manager_Obtain(struct LibraryManagerInterface *Self)
415 uint32 res;
416 __asm__ __volatile__(
417 "1: lwarx %0,0,%1\n"
418 "addic %0,%0,1\n"
419 "stwcx. %0,0,%1\n"
420 "bne- 1b"
421 : "=&r" (res)
422 : "r" (&Self->Data.RefCount)
423 : "cc", "memory");
425 return res;
428 STATIC uint32 _manager_Release(struct LibraryManagerInterface *Self)
430 uint32 res;
431 __asm__ __volatile__(
432 "1: lwarx %0,0,%1\n"
433 "addic %0,%0,-1\n"
434 "stwcx. %0,0,%1\n"
435 "bne- 1b"
436 : "=&r" (res)
437 : "r" (&Self->Data.RefCount)
438 : "cc", "memory");
440 return res;
443 STATIC CONST CONST_APTR lib_manager_vectors[] =
445 (CONST_APTR)_manager_Obtain,
446 (CONST_APTR)_manager_Release,
447 (CONST_APTR)NULL,
448 (CONST_APTR)NULL,
449 (CONST_APTR)LibOpen,
450 (CONST_APTR)LibClose,
451 (CONST_APTR)LibExpunge,
452 (CONST_APTR)NULL,
453 (CONST_APTR)-1
456 STATIC CONST struct TagItem lib_managerTags[] =
458 { MIT_Name, (Tag)"__library" },
459 { MIT_VectorTable, (Tag)lib_manager_vectors },
460 { MIT_Version, 1 },
461 { TAG_DONE, 0 }
464 /* ------------------- Library Interface(s) ------------------------ */
466 ULONG _MCCClass_Obtain(UNUSED struct Interface *Self)
468 return 0;
471 ULONG _MCCClass_Release(UNUSED struct Interface *Self)
473 return 0;
476 STATIC CONST CONST_APTR main_vectors[] =
478 (CONST_APTR)_MCCClass_Obtain,
479 (CONST_APTR)_MCCClass_Release,
480 (CONST_APTR)NULL,
481 (CONST_APTR)NULL,
482 (CONST_APTR)MCC_Query,
483 (CONST_APTR)-1
486 STATIC CONST struct TagItem mainTags[] =
488 { MIT_Name, (Tag)"main" },
489 { MIT_VectorTable, (Tag)main_vectors },
490 { MIT_Version, 1 },
491 { TAG_DONE, 0 }
494 STATIC CONST CONST_APTR libInterfaces[] =
496 (CONST_APTR)lib_managerTags,
497 (CONST_APTR)mainTags,
498 (CONST_APTR)NULL
501 // Our libraries always have to carry a 68k jump table with it, so
502 // lets define it here as extern, as we are going to link it to
503 // our binary here.
504 #ifndef NO_VECTABLE68K
505 extern CONST APTR VecTable68K[];
506 #endif
508 STATIC CONST struct TagItem libCreateTags[] =
510 { CLT_DataSize, sizeof(struct LibraryHeader) },
511 { CLT_InitFunc, (Tag)LibInit },
512 { CLT_Interfaces, (Tag)libInterfaces },
513 #ifndef NO_VECTABLE68K
514 { CLT_Vector68K, (Tag)VecTable68K },
515 #endif
516 { TAG_DONE, 0 }
519 #else
521 STATIC CONST CONST_APTR LibVectors[] =
523 #ifdef __MORPHOS__
524 (CONST_APTR)FUNCARRAY_32BIT_NATIVE,
525 #endif
526 #ifndef __AROS__
527 (CONST_APTR)LibOpen,
528 (CONST_APTR)LibClose,
529 (CONST_APTR)LibExpunge,
530 (CONST_APTR)LibNull,
531 (CONST_APTR)MCC_Query,
532 #else
533 (CONST_APTR)AROS_SLIB_ENTRY(LibOpen, __MCC_, 1),
534 (CONST_APTR)AROS_SLIB_ENTRY(LibClose, __MCC_, 2),
535 (CONST_APTR)AROS_SLIB_ENTRY(LibExpunge, __MCC_, 3),
536 (CONST_APTR)LibNull,
537 (CONST_APTR)AROS_SLIB_ENTRY(MCC_Query, __MCC_, 5),
538 #endif
539 (CONST_APTR)-1
542 STATIC CONST IPTR LibInitTab[] =
544 sizeof(struct LibraryHeader),
545 (IPTR)LibVectors,
546 (IPTR)NULL,
547 (IPTR)LibInit
550 #endif
552 /* ------------------- ROM Tag ------------------------ */
553 STATIC const USED_VAR struct Resident ROMTag =
555 RTC_MATCHWORD,
556 (struct Resident *)&ROMTag,
557 (struct Resident *)(&ROMTag + 1),
558 #if defined(__amigaos4__)
559 RTF_AUTOINIT|RTF_NATIVE, // The Library should be set up according to the given table.
560 #elif defined(__MORPHOS__)
561 RTF_AUTOINIT|RTF_EXTENDED|RTF_PPC,
562 #elif defined(__AROS__)
563 RTF_AUTOINIT|RTF_EXTENDED,
564 #else
565 RTF_AUTOINIT,
566 #endif
567 VERSION,
568 NT_LIBRARY,
570 (char *)UserLibName,
571 (char *)UserLibID+6, // +6 to skip '$VER: '
572 #if defined(__amigaos4__)
573 (APTR)libCreateTags, // This table is for initializing the Library.
574 #else
575 (APTR)LibInitTab,
576 #endif
577 #if defined(__MORPHOS__) || defined(__AROS__)
578 REVISION,
580 #endif
583 #if defined(__MORPHOS__)
585 * To tell the loader that this is a new emulppc elf and not
586 * one for the ppc.library.
587 * ** IMPORTANT **
589 const USED_VAR ULONG __abox__ = 1;
591 #endif /* __MORPHOS__ */
593 /****************************************************************************/
594 /* Stack enforcing function which allows to make sure that a function has */
595 /* enough stack space during its execution time */
596 /****************************************************************************/
598 #if defined(MIN_STACKSIZE) && !defined(__amigaos4__)
600 /* generic StackSwap() function which calls function() surrounded by
601 StackSwap() calls */
602 #if (defined(__mc68000__) && !defined(__AROS__))
603 ULONG stackswap_call(struct StackSwapStruct *stack,
604 ULONG (*function)(struct LibraryHeader *),
605 struct LibraryHeader *arg);
607 asm(".text \n\
608 .even \n\
609 .globl _stackswap_call \n\
610 _stackswap_call: \n\
611 moveml #0x3022,sp@- \n\
612 movel sp@(20),d3 \n\
613 movel sp@(24),a2 \n\
614 movel sp@(28),d2 \n\
615 movel _SysBase,a6 \n\
616 movel d3,a0 \n\
617 jsr a6@(-732:W) \n\
618 movel d2,sp@- \n\
619 jbsr a2@ \n\
620 movel d0,d2 \n\
621 addql #4,sp \n\
622 movel _SysBase,a6 \n\
623 movel d3,a0 \n\
624 jsr a6@(-732:W) \n\
625 movel d2,d0 \n\
626 moveml sp@+,#0x440c \n\
627 rts");
628 #elif defined(__MORPHOS__)
629 ULONG stackswap_call(struct StackSwapStruct *stack,
630 ULONG (*function)(struct LibraryHeader *),
631 struct LibraryHeader *arg)
633 struct PPCStackSwapArgs swapargs;
635 swapargs.Args[0] = (ULONG)arg;
637 return NewPPCStackSwap(stack, function, &swapargs);
639 #elif defined(__AROS__)
640 ULONG stackswap_call(struct StackSwapStruct *stack,
641 ULONG (*function)(struct LibraryHeader *),
642 struct LibraryHeader *arg)
644 struct StackSwapArgs swapargs;
646 swapargs.Args[0] = (IPTR)arg;
648 return NewStackSwap(stack, function, &swapargs);
650 #else
651 #error Bogus operating system
652 #endif
654 STATIC BOOL callMccFunction(ULONG (*function)(struct LibraryHeader *), struct LibraryHeader *arg)
656 BOOL success = FALSE;
657 struct Task *tc;
658 ULONG stacksize;
660 // retrieve the task structure for the
661 // current task
662 tc = FindTask(NULL);
664 #if defined(__MORPHOS__)
665 // In MorphOS we have two stacks. One for PPC code and another for 68k code.
666 // We are only interested in the PPC stack.
667 NewGetTaskAttrsA(tc, &stacksize, sizeof(ULONG), TASKINFOTYPE_STACKSIZE, NULL);
668 #else
669 // on all other systems we query via SPUpper-SPLower calculation
670 stacksize = (IPTR)tc->tc_SPUpper - (IPTR)tc->tc_SPLower;
671 #endif
673 // Swap stacks only if current stack is insufficient
674 if(stacksize < MIN_STACKSIZE)
676 struct StackSwapStruct *stack;
678 if((stack = AllocVec(sizeof(*stack), MEMF_PUBLIC)) != NULL)
680 if((stack->stk_Lower = AllocVec(MIN_STACKSIZE, MEMF_PUBLIC)) != NULL)
682 // perform the StackSwap
683 #if defined(__AROS__)
684 // AROS uses an APTR type for stk_Upper
685 stack->stk_Upper = (APTR)((IPTR)stack->stk_Lower + MIN_STACKSIZE);
686 #else
687 // all other systems use ULONG
688 stack->stk_Upper = (ULONG)stack->stk_Lower + MIN_STACKSIZE;
689 #endif
690 stack->stk_Pointer = (APTR)stack->stk_Upper;
692 // call routine but with embedding it into a [NewPPC]StackSwap()
693 success = stackswap_call(stack, function, arg);
695 FreeVec(stack->stk_Lower);
697 FreeVec(stack);
700 else
701 success = function(arg);
703 return success;
705 #else // MIN_STACKSIZE && __amigaos4__
706 #define callMccFunction(func, arg) func(arg)
707 #endif // MIN_STACKSIZE && __amigaos4__
709 /******************************************************************************/
710 /* Wrapper functions to perform certain tasks in our LibInit/LibOpen etc. */
711 /******************************************************************************/
713 /* open and init all necessary library and stuff in the LibInit() phase */
714 STATIC ULONG mccLibInit(struct LibraryHeader *base)
716 // now that this library/class is going to be initialized for the first time
717 // we go and open all necessary libraries on our own
718 #if defined(__amigaos4__)
719 if((DOSBase = OpenLibrary("dos.library", 36)) &&
720 GETINTERFACE(IDOS, struct DOSIFace *, DOSBase))
721 if((GfxBase = OpenLibrary("graphics.library", 36)) &&
722 GETINTERFACE(IGraphics, struct GraphicsIFace *, GfxBase))
723 if((IntuitionBase = OpenLibrary("intuition.library", 36)) &&
724 GETINTERFACE(IIntuition, struct IntuitionIFace *, IntuitionBase))
725 if((UtilityBase = OpenLibrary("utility.library", 36)) &&
726 GETINTERFACE(IUtility, struct UtilityIFace *, UtilityBase))
727 #else
728 if((DOSBase = (struct DosLibrary*)OpenLibrary("dos.library", 36)) &&
729 (GfxBase = (struct GfxBase*)OpenLibrary("graphics.library", 36)) &&
730 (IntuitionBase = (struct IntuitionBase*)OpenLibrary("intuition.library", 36)) &&
731 (UtilityBase = (APTR)OpenLibrary("utility.library", 36)))
732 #endif
734 // we have to please the internal utilitybase
735 // pointers of libnix and clib2
736 #if !defined(__NEWLIB__)
737 __UtilityBase = (APTR)UtilityBase;
738 #if defined(__amigaos4__)
739 __IUtility = IUtility;
740 #endif
741 #endif
743 #if defined(DEBUG)
744 SetupDebug();
745 #endif
747 if((MUIMasterBase = OpenLibrary(MUIMASTER_NAME, MASTERVERSION)) &&
748 GETINTERFACE(IMUIMaster, struct MUIMasterIFace*, MUIMasterBase))
750 #if defined(PRECLASSINIT)
751 if(PreClassInit())
752 #endif
754 #ifdef SUPERCLASS
755 ThisClass = MUI_CreateCustomClass(&base->lh_Library, (STRPTR)SUPERCLASS, NULL, sizeof(struct INSTDATA), ENTRY(_Dispatcher));
756 if(ThisClass)
757 #endif
759 #ifdef SUPERCLASSP
760 if((ThisClassP = MUI_CreateCustomClass(&base->lh_Library, (STRPTR)SUPERCLASSP, NULL, sizeof(struct INSTDATAP), ENTRY(_DispatcherP))))
761 #endif
763 #ifdef SUPERCLASS
764 #define THISCLASS ThisClass
765 #else
766 #define THISCLASS ThisClassP
767 #endif
769 // in case the user defined an own ClassInit()
770 // function we call it protected by a semaphore as
771 // this user may be stupid and break the Forbid() state
772 // of LibInit()
773 #if defined(CLASSINIT)
774 if(ClassInit(&base->lh_Library))
775 #endif
777 // everything was successfully so lets
778 // make sure we return TRUE
779 return TRUE;
781 #if defined(CLASSINIT)
782 else
783 E(DBF_STARTUP, "ClassInit(%s) failed", CLASS);
784 #endif
786 // if we pass this point than an error
787 // occurred and we have to cleanup
788 #if defined(SUPERCLASSP)
789 MUI_DeleteCustomClass(ThisClassP);
790 ThisClassP = NULL;
791 #endif
794 #if defined(SUPERCLASS)
795 MUI_DeleteCustomClass(ThisClass);
796 ThisClass = NULL;
797 #endif
801 DROPINTERFACE(IMUIMaster);
802 CloseLibrary(MUIMasterBase);
803 MUIMasterBase = NULL;
806 DROPINTERFACE(IUtility);
807 CloseLibrary((struct Library *)UtilityBase);
808 UtilityBase = NULL;
811 if(IntuitionBase)
813 DROPINTERFACE(IIntuition);
814 CloseLibrary((struct Library *)IntuitionBase);
815 IntuitionBase = NULL;
818 if(GfxBase)
820 DROPINTERFACE(IGraphics);
821 CloseLibrary((struct Library *)GfxBase);
822 GfxBase = NULL;
825 if(DOSBase)
827 DROPINTERFACE(IDOS);
828 CloseLibrary((struct Library *)DOSBase);
829 DOSBase = NULL;
832 E(DBF_STARTUP, "mccLibInit(%s) failed", CLASS);
833 return FALSE;
836 /* expunge everything we previously opened and call user definable functions */
837 STATIC ULONG mccLibExpunge(UNUSED struct LibraryHeader *base)
839 // in case the user specified that he has an own class
840 // expunge function we call it right here, not caring about
841 // any return value.
842 #if defined(CLASSEXPUNGE)
843 ClassExpunge(&base->lh_Library);
844 #endif
846 // now we remove our own stuff here step-by-step
847 #ifdef SUPERCLASSP
848 if(ThisClassP)
850 MUI_DeleteCustomClass(ThisClassP);
851 ThisClassP = NULL;
853 #endif
855 #ifdef SUPERCLASS
856 if(ThisClass)
858 MUI_DeleteCustomClass(ThisClass);
859 ThisClass = NULL;
861 #endif
863 // we inform the user that all main class expunge stuff
864 // is finished, if he want's to get informed.
865 #if defined(POSTCLASSEXPUNGE)
866 PostClassExpunge();
867 #endif
869 #if defined(DEBUG)
870 CleanupDebug();
871 #endif
873 // cleanup the various library bases and such
874 if(MUIMasterBase)
876 DROPINTERFACE(IMUIMaster);
877 CloseLibrary(MUIMasterBase);
878 MUIMasterBase = NULL;
881 if(UtilityBase)
883 DROPINTERFACE(IUtility);
884 CloseLibrary((struct Library *)UtilityBase);
885 UtilityBase = NULL;
888 if(IntuitionBase)
890 DROPINTERFACE(IIntuition);
891 CloseLibrary((struct Library *)IntuitionBase);
892 IntuitionBase = NULL;
895 if(GfxBase)
897 DROPINTERFACE(IGraphics);
898 CloseLibrary((struct Library *)GfxBase);
899 GfxBase = NULL;
902 if(DOSBase)
904 DROPINTERFACE(IDOS);
905 CloseLibrary((struct Library *)DOSBase);
906 DOSBase = NULL;
909 return TRUE;
912 /* we call the user definable function here only */
913 #if defined(CLASSOPEN)
914 STATIC ULONG mccLibOpen(struct LibraryHeader *base)
916 return ClassOpen(&base->lh_Library);
918 #endif
920 /* we call the user definable function here only */
921 #if defined(CLASSCLOSE)
922 STATIC ULONG mccLibClose(struct LibraryHeader *base)
924 ClassClose(&base->lh_Library);
925 return TRUE;
927 #endif
929 /******************************************************************************/
930 /* Standard Library Functions, all of them are called in Forbid() state. */
931 /******************************************************************************/
933 #if defined(__amigaos4__)
934 STATIC struct LibraryHeader * LibInit(struct LibraryHeader *base, BPTR librarySegment, struct ExecIFace *pIExec)
936 struct Library *sb = (struct Library *)pIExec->Data.LibBase;
937 IExec = pIExec;
938 #elif defined(__MORPHOS__)
939 STATIC struct LibraryHeader * LibInit(struct LibraryHeader *base, BPTR librarySegment, struct ExecBase *sb)
941 #elif defined(__AROS__)
942 AROS_UFH3 (struct LibraryHeader *, LibInit,
943 AROS_UFHA(struct LibraryHeader *, base, D0),
944 AROS_UFHA(BPTR, librarySegment, A0),
945 AROS_UFHA(struct ExecBase *, sb, A6)
948 AROS_USERFUNC_INIT
949 #else
950 STATIC struct LibraryHeader * LIBFUNC LibInit(REG(d0, struct LibraryHeader *base), REG(a0, BPTR librarySegment), REG(a6, struct ExecBase *sb))
952 #endif
954 SysBase = sb;
956 // make sure that this is really a 68020+ machine if optimized for 020+
957 #if _M68060 || _M68040 || _M68030 || _M68020 || __mc68020 || __mc68030 || __mc68040 || __mc68060
958 if(!(SysBase->AttnFlags & AFF_68020))
959 return(NULL);
960 #endif
962 #if defined(__amigaos4__) && defined(__NEWLIB__)
963 if((NewlibBase = OpenLibrary("newlib.library", 3)) &&
964 GETINTERFACE(INewlib, struct Interface*, NewlibBase))
965 #endif
967 BOOL success = FALSE;
969 D(DBF_STARTUP, "LibInit(" CLASS ")");
971 // cleanup the library header structure beginning with the
972 // library base, even if that is done automcatically, we explicitly
973 // do it here for consistency reasons.
974 base->lh_Library.lib_Node.ln_Type = NT_LIBRARY;
975 base->lh_Library.lib_Node.ln_Pri = 0;
976 base->lh_Library.lib_Node.ln_Name = (char *)UserLibName;
977 base->lh_Library.lib_Flags = LIBF_CHANGED | LIBF_SUMUSED;
978 base->lh_Library.lib_IdString = (char *)UserLibID; // here without +6 or otherwise MUI doesn't identify it.
979 base->lh_Library.lib_Version = VERSION;
980 base->lh_Library.lib_Revision = REVISION;
982 // init our protecting semaphore and the
983 // initialized flag variable
984 memset(&base->lh_Semaphore, 0, sizeof(base->lh_Semaphore));
985 InitSemaphore(&base->lh_Semaphore);
987 // protect mccLibInit()
988 ObtainSemaphore(&base->lh_Semaphore);
990 // If we are not running on AmigaOS4 (no stackswap required) we go and
991 // do an explicit StackSwap() in case the user wants to make sure we
992 // have enough stack for his user functions
993 success = callMccFunction(mccLibInit, base);
995 // unprotect
996 ReleaseSemaphore(&base->lh_Semaphore);
998 // check if everything worked out fine
999 if(success == TRUE)
1001 // everything was successfully so lets
1002 // set the initialized value and contiue
1003 // with the class open phase
1004 base->lh_Segment = librarySegment;
1006 // return the library base as success
1007 return base;
1010 #if defined(__amigaos4__) && defined(__NEWLIB__)
1011 if(NewlibBase)
1013 DROPINTERFACE(INewlib);
1014 CloseLibrary(NewlibBase);
1015 NewlibBase = NULL;
1017 #endif
1020 return(NULL);
1021 #ifdef __AROS__
1022 AROS_USERFUNC_EXIT
1023 #endif
1026 /*****************************************************************************************************/
1027 /*****************************************************************************************************/
1029 #ifndef __amigaos4__
1030 #define DeleteLibrary(LIB) \
1031 FreeMem((STRPTR)(LIB)-(LIB)->lib_NegSize, (ULONG)((LIB)->lib_NegSize+(LIB)->lib_PosSize))
1032 #endif
1034 STATIC BPTR LibDelete(struct LibraryHeader *base)
1036 #if defined(__amigaos4__)
1037 struct ExecIFace *IExec = (struct ExecIFace *)(*(struct ExecBase **)4)->MainInterface;
1038 #endif
1039 BPTR rc;
1041 // remove the library base from exec's lib list in advance
1042 Remove((struct Node *)base);
1044 // protect mccLibExpunge()
1045 ObtainSemaphore(&base->lh_Semaphore);
1047 // make sure we have enough stack here
1048 callMccFunction(mccLibExpunge, base);
1050 // unprotect
1051 ReleaseSemaphore(&base->lh_Semaphore);
1053 #if defined(__amigaos4__) && defined(__NEWLIB__)
1054 if(NewlibBase)
1056 DROPINTERFACE(INewlib);
1057 CloseLibrary(NewlibBase);
1058 NewlibBase = NULL;
1060 #endif
1062 // make sure the system deletes the library as well.
1063 rc = base->lh_Segment;
1064 DeleteLibrary(&base->lh_Library);
1066 return rc;
1069 #if defined(__amigaos4__)
1070 STATIC BPTR LibExpunge(struct LibraryManagerInterface *Self)
1072 struct LibraryHeader *base = (struct LibraryHeader *)Self->Data.LibBase;
1073 #elif defined(__MORPHOS__)
1074 STATIC BPTR LibExpunge(void)
1076 struct LibraryHeader *base = (struct LibraryHeader *)REG_A6;
1077 #elif defined(__AROS__)
1078 AROS_LH1 (BPTR, LibExpunge,
1079 AROS_LHA(UNUSED struct LibraryHeader *, extralh, D0),
1080 struct LibraryHeader *, base, 3, __MCC_
1083 AROS_LIBFUNC_INIT
1084 #else
1085 STATIC BPTR LIBFUNC LibExpunge(REG(a6, struct LibraryHeader *base))
1087 #endif
1088 BPTR rc;
1090 D(DBF_STARTUP, "LibExpunge(" CLASS "): %ld", base->lh_Library.lib_OpenCnt);
1092 // in case our open counter is still > 0, we have
1093 // to set the late expunge flag and return immediately
1094 if(base->lh_Library.lib_OpenCnt > 0)
1096 base->lh_Library.lib_Flags |= LIBF_DELEXP;
1097 rc = 0;
1099 else
1101 rc = LibDelete(base);
1104 return(rc);
1105 #ifdef __AROS__
1106 AROS_LIBFUNC_EXIT
1107 #endif
1110 /*****************************************************************************************************/
1111 /*****************************************************************************************************/
1113 #if defined(__amigaos4__)
1114 STATIC struct LibraryHeader *LibOpen(struct LibraryManagerInterface *Self, ULONG version UNUSED)
1116 struct LibraryHeader *base = (struct LibraryHeader *)Self->Data.LibBase;
1117 #elif defined(__MORPHOS__)
1118 STATIC struct LibraryHeader *LibOpen(void)
1120 struct LibraryHeader *base = (struct LibraryHeader *)REG_A6;
1121 #elif defined(__AROS__)
1122 AROS_LH1 (struct LibraryHeader *, LibOpen,
1123 AROS_LHA (UNUSED ULONG, version, D0),
1124 struct LibraryHeader *, base, 1, __MCC_
1127 AROS_LIBFUNC_INIT
1128 #else
1129 STATIC struct LibraryHeader * LIBFUNC LibOpen(REG(d0, UNUSED ULONG version), REG(a6, struct LibraryHeader *base))
1131 #endif
1132 struct LibraryHeader *res = NULL;
1134 D(DBF_STARTUP, "LibOpen(" CLASS "): %ld", base->lh_Library.lib_OpenCnt);
1136 // LibOpen(), LibClose() and LibExpunge() are called while the system is in
1137 // Forbid() state. That means that these functions should be quick and should
1138 // not break this Forbid()!! Therefore the open counter should be increased
1139 // as the very first instruction during LibOpen(), because a ClassOpen()
1140 // which breaks a Forbid() and another task calling LibExpunge() will cause
1141 // to expunge this library while it is not yet fully initialized. A crash
1142 // is unavoidable then. Even the semaphore does not guarantee 100% protection
1143 // against such a race condition, because waiting for the semaphore to be
1144 // obtained will effectively break the Forbid()!
1146 // increase the open counter ahead of anything else
1147 base->lh_Library.lib_OpenCnt++;
1149 // delete the late expunge flag
1150 base->lh_Library.lib_Flags &= ~LIBF_DELEXP;
1152 // check if the user defined a ClassOpen() function
1153 #if defined(CLASSOPEN)
1155 struct ExecIFace *IExec = (struct ExecIFace *)(*(struct ExecBase **)4)->MainInterface;
1156 BOOL success = FALSE;
1158 // protect
1159 ObtainSemaphore(&base->lh_Semaphore);
1161 // make sure we have enough stack here
1162 success = callMccFunction(mccLibOpen, base);
1164 // here we call the user-specific function for LibOpen() where
1165 // he can do whatever he wants because of the semaphore protection.
1166 if(success == TRUE)
1167 res = base;
1168 else
1170 E(DBF_STARTUP, "ClassOpen(" CLASS ") failed");
1172 // decrease the open counter again
1173 base->lh_Library.lib_OpenCnt--;
1176 // release the semaphore
1177 ReleaseSemaphore(&base->lh_Semaphore);
1179 #else
1180 res = base;
1181 #endif
1183 return res;
1184 #ifdef __AROS__
1185 AROS_LIBFUNC_EXIT
1186 #endif
1189 /*****************************************************************************************************/
1190 /*****************************************************************************************************/
1192 #if defined(__amigaos4__)
1193 STATIC BPTR LibClose(struct LibraryManagerInterface *Self)
1195 struct LibraryHeader *base = (struct LibraryHeader *)Self->Data.LibBase;
1196 #elif defined(__MORPHOS__)
1197 STATIC BPTR LibClose(void)
1199 struct LibraryHeader *base = (struct LibraryHeader *)REG_A6;
1200 #elif defined(__AROS__)
1201 AROS_LH0 (BPTR, LibClose,
1202 struct LibraryHeader *, base, 2, __MCC_
1205 AROS_LIBFUNC_INIT
1206 #else
1207 STATIC BPTR LIBFUNC LibClose(REG(a6, struct LibraryHeader *base))
1209 #endif
1210 BPTR rc = 0;
1212 D(DBF_STARTUP, "LibClose(" CLASS "): %ld", base->lh_Library.lib_OpenCnt);
1214 // check if the user defined a ClassClose() function
1215 #if defined(CLASSCLOSE)
1217 struct ExecIFace *IExec = (struct ExecIFace *)(*(struct ExecBase **)4)->MainInterface;
1219 // protect
1220 ObtainSemaphore(&base->lh_Semaphore);
1222 // make sure we have enough stack here
1223 success = callMccFunction(mccLibClose, base);
1225 // release the semaphore
1226 ReleaseSemaphore(&base->lh_Semaphore);
1228 #endif
1230 // decrease the open counter
1231 base->lh_Library.lib_OpenCnt--;
1233 // in case the opern counter is <= 0 we can
1234 // make sure that we free everything
1235 if(base->lh_Library.lib_OpenCnt <= 0)
1237 // in case the late expunge flag is set we go and
1238 // expunge the library base right now
1239 if(base->lh_Library.lib_Flags & LIBF_DELEXP)
1241 rc = LibDelete(base);
1245 return rc;
1246 #ifdef __AROS__
1247 AROS_LIBFUNC_EXIT
1248 #endif
1251 /*****************************************************************************************************/
1252 /*****************************************************************************************************/
1254 #if defined(__amigaos4__)
1255 STATIC IPTR LIBFUNC MCC_Query(UNUSED struct Interface *self, REG(d0, LONG which))
1257 #elif defined(__MORPHOS__)
1258 STATIC IPTR MCC_Query(void)
1260 LONG which = (LONG)REG_D0;
1261 #elif defined(__AROS__)
1262 AROS_LH1(IPTR, MCC_Query,
1263 AROS_LHA(LONG, which, D0),
1264 UNUSED struct LibraryHeader *, base, 5, __MCC_
1267 AROS_LIBFUNC_INIT
1268 #else
1269 STATIC IPTR LIBFUNC MCC_Query(REG(d0, LONG which))
1271 #endif
1273 D(DBF_STARTUP, "MCC_Query(" CLASS "): %ld", which);
1275 switch (which)
1277 #ifdef SUPERCLASS
1278 case 0: return((IPTR)ThisClass);
1279 #endif
1281 #ifdef SUPERCLASSP
1282 case 1: return((IPTR)ThisClassP);
1283 #endif
1285 #ifdef PREFSIMAGEOBJECT
1286 case 2:
1288 Object *obj = PREFSIMAGEOBJECT;
1289 return((IPTR)obj);
1291 #endif
1293 #ifdef ONLYGLOBAL
1294 case 3:
1296 return(TRUE);
1298 #endif
1300 #ifdef INFOCLASS
1301 case 4:
1303 return(TRUE);
1305 #endif
1307 #ifdef USEDCLASSES
1308 case 5:
1310 return((IPTR)USEDCLASSES);
1312 #endif
1314 #ifdef USEDCLASSESP
1315 case 6:
1317 return((IPTR)USEDCLASSESP);
1319 #endif
1321 #ifdef SHORTHELP
1322 case 7:
1324 return((IPTR)SHORTHELP);
1326 #endif
1329 return(0);
1330 #ifdef __AROS__
1331 AROS_LIBFUNC_EXIT
1332 #endif
1335 #ifdef __cplusplus
1337 #endif