revert between 56095 -> 55830 in arch
[AROS.git] / workbench / classes / zune / betterstring / include / mccinit.c
blob0e95170168adff4eab70e8c2ce33d7526028bd07
1 /*******************************************************************************
3 Name: mccinit.c
4 Versionstring: $VER: mccinit.c 1.26 (06.03.2013)
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.
70 1.25 20.12.2010 : minimum required system version is now OS3.0 (V39).
71 1.26 06.03.2013 : removed _start entry point. This must be defined separately
72 to ensure it is the very first piece of code in the final
73 binary file.
74 WIP 24.08.2013 fix for making it compilabe for both ABIv1 and v0 of AROS.
76 About:
78 The purpose of this source file is to provide a template for the library init
79 code for a creation of an own MUI custom class (mcc/mcp) for AmigaOS4,
80 AmigaOS3 and MorphOS. By directly including this file (#include "mccinit.c")
81 and defining certain preprocessor values, a MUI developer doesn't have to
82 care about library init stuff which is normally highly system dependent and
83 various between different Amiga operating systems.
85 Usage:
87 This file should be included by another source file (e.g. 'library.c') in
88 your main development branch while certain preprocessor macros right before
89 the include statement can be defined to change the behaviour of mccinit.c.
90 These possible macros are:
92 USERLIBID (char*) - version string for the mcc/mcp (exluding $VER:)
93 VERSION (int) - version number (must match USERLIBID)
94 REVISION (int) - revision number (must match USERLIBID)
95 CLASS (char*) - class name (including .mcc/.mcp)
96 MASTERVERSION (int) - the minimun required muimaster version
97 (default: MUIMASTER_VMIN)
98 MIN_STACKSIZE (int) - if defined, the specified minimum stack size
99 will be enforced when calling all user functions
100 like ClassXXXX() and PreClassXXX().
102 MCC only:
103 --------
104 SUPERCLASS (char*) - superclass ID of MCC (e.g. MUIC_Area)
105 INSTDATA - name of instance data structure of MCC (e.g. InstData)
106 USEDCLASSES - name of NULL terminated string array which contains
107 names of other required custom classes for MCC.
108 _Dispatcher - name of Dispatcher function for MCC
110 MCP only:
111 -------
112 SUPERCLASSP (char*) - superclass ID of MCP (e.g. MUIC_Mccprefs)
113 INSTDATAP - name of instance data structure of MCP
114 USEDCLASSESP - name of NULL terminated string array which contains
115 names of other required custom classes for MCC.
116 SHORTHELP (char*) - alternative help text for prefs program's listview
117 PREFSIMAGEOBJECT - pointer to the image object for the MCP
118 _DispatcherP - name of Dispatcher function for MCP
120 In addition, the following defines and functions can be defined or are
121 required:
123 CLASSINIT - if defined, a "BOOL ClassInit(struct Library *base)"
124 function can be defined in your own code and will be called
125 right after the general library initialization are
126 finished. This function should then open own libraries
127 or do own library initialization tasks as it is only called
128 once at the very first library/class open.
130 CLASSEXPUNGE - if defined a "VOID ClassExpunge(struct Library *base)"
131 function can be defined in your own code and will be called
132 as soon as the library will be freed/expunged by the
133 operating system. In this function you should close/free
134 stuff you normally opened/allocated in CLASSINIT.
136 CLASSOPEN - if defined, a "BOOL ClassOpen(struct Library *base)"
137 function can be defined in your own code and will be called
138 right after each single application opens the custom class.
139 In this function you can then set flags or do library open
140 specific tasks.
142 CLASSCLOSE - if defined a "VOID ClassClose(struct Library *base)"
143 function can be defined in your own code and will be called
144 right after the library was successfully flagged as closed
145 by the CloseLibrary() call of an application.
148 PRECLASSINIT - if defined a "BOOL PreClassInit(struct Library *base)"
149 function can be defined and will be called right _before_
150 and library initialization takes place.
152 POSTCLASSEXPUNGE - if defined a "BOOL PostClassExpunge(struct Library *base)"
153 function can be defined and will be called right _after_
154 the custom class was free via MUI_DeleteCustomClass() in
155 the library expunge phase.
157 Warning:
158 -------
159 The above class functions are normally called by the operating system
160 in a Forbid()/Permit() state. That means you are supposed to make sure that
161 your operations doesn't break the Forbid() state or otherwise you may run
162 into a race condition. However, we have added semaphore locking to partly
163 protect you from that case - but you should still consider doing processor
164 intensitive tasks in a library's own function instead of using those
165 class initialization functions.
167 *******************************************************************************/
169 /******************************************************************************/
170 /* Includes */
171 /******************************************************************************/
173 #include <string.h>
175 #ifdef __MORPHOS__
176 #include <emul/emulinterface.h>
177 #include <emul/emulregs.h>
178 #endif
180 #include <exec/types.h>
181 #include <exec/memory.h>
182 #include <exec/libraries.h>
183 #include <exec/semaphores.h>
184 #include <exec/resident.h>
185 #include <exec/execbase.h>
186 #include <dos/dos.h>
188 #include <proto/exec.h>
189 #include <proto/muimaster.h>
190 #include <proto/utility.h>
191 #include <proto/dos.h>
192 #include <proto/graphics.h>
193 #include <proto/intuition.h>
195 #ifdef __AROS__
196 #include <aros/libcall.h>
197 #include <utility/utility.h>
198 #ifdef AROS_ABI_V1
199 #include <aros/config.h>
200 #endif
201 #endif
203 #include "SDI_compiler.h"
205 #if defined(__amigaos4__)
206 struct Library *MUIMasterBase = NULL;
207 struct Library *SysBase = NULL;
208 struct Library *UtilityBase = NULL;
209 struct Library *DOSBase = NULL;
210 struct Library *GfxBase = NULL;
211 struct Library *IntuitionBase = NULL;
212 struct ExecIFace *IExec = NULL;
213 struct MUIMasterIFace *IMUIMaster = NULL;
214 struct UtilityIFace *IUtility = NULL;
215 struct DOSIFace *IDOS = NULL;
216 struct GraphicsIFace *IGraphics = NULL;
217 struct IntuitionIFace *IIntuition = NULL;
218 #if defined(__NEWLIB__)
219 struct Library *NewlibBase = NULL;
220 struct Interface *INewlib = NULL;
221 #endif
222 #else
223 struct Library *MUIMasterBase = NULL;
224 struct ExecBase *SysBase = NULL;
225 #if defined(__AROS__)
226 struct UtilityBase *UtilityBase = NULL;
227 #else
228 struct Library *UtilityBase = NULL;
229 #endif
230 struct DosLibrary *DOSBase = NULL;
231 struct GfxBase *GfxBase = NULL;
232 struct IntuitionBase *IntuitionBase = NULL;
233 #endif
235 #ifdef __cplusplus
236 extern "C" {
237 #endif
239 // we place a stack cookie in the binary so that
240 // newer OS version can directly take the specified
241 // number for the ramlib process
242 #if defined(MIN_STACKSIZE)
244 // transforms a define into a string
245 #define STR(x) STR2(x)
246 #define STR2(x) #x
248 #ifdef __amigaos4__
249 STATIC const char USED_VAR stack_size[] = "$STACK:" STR(MIN_STACKSIZE) "\n";
250 #endif
251 #endif
253 /* The name of the class will also become the name of the library. */
254 /* We need a pointer to this string in our ROMTag (see below). */
255 STATIC const char UserLibName[] = CLASS;
256 STATIC const char UserLibID[] = "$VER: " USERLIBID;
258 #ifdef SUPERCLASS
259 STATIC struct MUI_CustomClass *ThisClass = NULL;
260 DISPATCHERPROTO(_Dispatcher);
261 #endif
263 #ifdef SUPERCLASSP
264 STATIC struct MUI_CustomClass *ThisClassP = NULL;
265 DISPATCHERPROTO(_DispatcherP);
266 #endif
268 #ifdef __GNUC__
270 #if !defined(__NEWLIB__)
271 #if defined(__amigaos4__)
272 extern struct Library *__UtilityBase; // clib2
273 extern struct UtilityIFace* __IUtility; // clib2
274 #else
275 struct Library *__UtilityBase = NULL; // required by libnix & clib2
276 #endif
277 #endif
279 /* these one are needed copies for libnix.a */
280 #ifdef __libnix__
281 #ifdef USE_MATHIEEEDOUBBASBASE
282 struct Library *__MathIeeeDoubBasBase = NULL;
283 #endif
284 #ifdef USE_MATHIEEEDOUBTRANSBASE
285 struct Library *__MathIeeeDoubTransBase = NULL;
286 #endif
287 #endif
289 #endif /* __GNUC__ */
292 // define own macros for the OS4 interfaces
293 #undef GETINTERFACE
294 #undef DROPINTERFACE
295 #if defined(__amigaos4__)
296 #define GETINTERFACE(iface, type, base) (iface = (type)GetInterface((struct Library *)(base), "main", 1L, NULL))
297 #define DROPINTERFACE(iface) (DropInterface((struct Interface *)iface), iface = NULL)
298 #else
299 #define GETINTERFACE(iface, type, base) TRUE
300 #define DROPINTERFACE(iface)
301 #endif
303 // in case the user didn't specify an own minimum
304 // muimaster version we increase it here.
305 #ifndef MASTERVERSION
306 #define MASTERVERSION MUIMASTER_VMIN
307 #endif
309 /* Our library structure, consisting of a struct Library, a segment pointer */
310 /* and a semaphore. We need the semaphore to protect init/exit stuff in our */
311 /* open/close fuSnctions */
312 struct LibraryHeader
314 struct Library lh_Library;
315 UWORD lh_Pad1;
316 BPTR lh_Segment;
317 struct SignalSemaphore lh_Semaphore;
318 UWORD lh_Pad2;
321 /******************************************************************************/
322 /* Local Structures & Prototypes */
323 /******************************************************************************/
325 #if defined(__amigaos4__)
327 STATIC struct LibraryHeader * LIBFUNC LibInit (struct LibraryHeader *base, BPTR librarySegment, struct ExecIFace *pIExec);
328 STATIC BPTR LIBFUNC LibExpunge (struct LibraryManagerInterface *Self);
329 STATIC struct LibraryHeader * LIBFUNC LibOpen (struct LibraryManagerInterface *Self, ULONG version);
330 STATIC BPTR LIBFUNC LibClose (struct LibraryManagerInterface *Self);
331 STATIC IPTR LIBFUNC MCC_Query (UNUSED struct Interface *self, REG(d0, LONG which));
333 #elif defined(__MORPHOS__)
335 STATIC struct LibraryHeader * LIBFUNC LibInit (struct LibraryHeader *base, BPTR librarySegment, struct ExecBase *sb);
336 STATIC BPTR LIBFUNC LibExpunge (void);
337 STATIC struct LibraryHeader * LIBFUNC LibOpen (void);
338 STATIC BPTR LIBFUNC LibClose (void);
339 STATIC LONG LIBFUNC LibNull (void);
340 STATIC IPTR LIBFUNC MCC_Query (void);
342 #elif defined(__AROS__)
344 AROS_UFP3 (struct LibraryHeader *, LibInit,
345 AROS_UFPA(struct LibraryHeader *, base, D0),
346 AROS_UFPA(BPTR, librarySegment, A0),
347 AROS_UFPA(struct ExecBase *, sb, A6)
349 AROS_LD1(BPTR, LibExpunge,
350 AROS_LPA(struct LibraryHeader *, base, D0),
351 struct LibraryHeader *, base, 3, __MCC_
353 AROS_LD1 (struct LibraryHeader *, LibOpen,
354 AROS_LHA (ULONG, version, D0),
355 struct LibraryHeader *, base, 1, __MCC_
357 AROS_LD0 (BPTR, LibClose,
358 struct LibraryHeader *, base, 2, __MCC_
360 AROS_LD1(IPTR, MCC_Query,
361 AROS_LHA(LONG, what, D0),
362 struct LibraryHeader *, LIBBASE, 5, __MCC_
365 #else
367 STATIC struct LibraryHeader * LIBFUNC LibInit (REG(d0, struct LibraryHeader *base), REG(a0, BPTR librarySegment), REG(a6, struct ExecBase *sb));
368 STATIC BPTR LIBFUNC LibExpunge (REG(a6, struct LibraryHeader *base));
369 STATIC struct LibraryHeader * LIBFUNC LibOpen (REG(d0, ULONG version), REG(a6, struct LibraryHeader *base));
370 STATIC BPTR LIBFUNC LibClose (REG(a6, struct LibraryHeader *base));
371 STATIC LONG LIBFUNC LibNull (void);
372 STATIC IPTR LIBFUNC MCC_Query (REG(d0, LONG which));
374 #endif
376 /******************************************************************************/
377 /* Dummy LibNull() function */
378 /******************************************************************************/
380 #if !defined(__amigaos4__)
381 STATIC LONG LIBFUNC LibNull(VOID)
383 return(0);
385 #endif
387 /******************************************************************************/
388 /* Local data structures */
389 /******************************************************************************/
391 #if defined(__amigaos4__)
392 /* ------------------- OS4 Manager Interface ------------------------ */
393 STATIC uint32 _manager_Obtain(struct LibraryManagerInterface *Self)
395 uint32 res;
396 __asm__ __volatile__(
397 "1: lwarx %0,0,%1\n"
398 "addic %0,%0,1\n"
399 "stwcx. %0,0,%1\n"
400 "bne- 1b"
401 : "=&r" (res)
402 : "r" (&Self->Data.RefCount)
403 : "cc", "memory");
405 return res;
408 STATIC uint32 _manager_Release(struct LibraryManagerInterface *Self)
410 uint32 res;
411 __asm__ __volatile__(
412 "1: lwarx %0,0,%1\n"
413 "addic %0,%0,-1\n"
414 "stwcx. %0,0,%1\n"
415 "bne- 1b"
416 : "=&r" (res)
417 : "r" (&Self->Data.RefCount)
418 : "cc", "memory");
420 return res;
423 STATIC CONST CONST_APTR lib_manager_vectors[] =
425 (CONST_APTR)_manager_Obtain,
426 (CONST_APTR)_manager_Release,
427 (CONST_APTR)NULL,
428 (CONST_APTR)NULL,
429 (CONST_APTR)LibOpen,
430 (CONST_APTR)LibClose,
431 (CONST_APTR)LibExpunge,
432 (CONST_APTR)NULL,
433 (CONST_APTR)-1
436 STATIC CONST struct TagItem lib_managerTags[] =
438 { MIT_Name, (Tag)"__library" },
439 { MIT_VectorTable, (Tag)lib_manager_vectors },
440 { MIT_Version, 1 },
441 { TAG_DONE, 0 }
444 /* ------------------- Library Interface(s) ------------------------ */
446 ULONG _MCCClass_Obtain(UNUSED struct Interface *Self)
448 return 0;
451 ULONG _MCCClass_Release(UNUSED struct Interface *Self)
453 return 0;
456 STATIC CONST CONST_APTR main_vectors[] =
458 (CONST_APTR)_MCCClass_Obtain,
459 (CONST_APTR)_MCCClass_Release,
460 (CONST_APTR)NULL,
461 (CONST_APTR)NULL,
462 (CONST_APTR)MCC_Query,
463 (CONST_APTR)-1
466 STATIC CONST struct TagItem mainTags[] =
468 { MIT_Name, (Tag)"main" },
469 { MIT_VectorTable, (Tag)main_vectors },
470 { MIT_Version, 1 },
471 { TAG_DONE, 0 }
474 STATIC CONST CONST_APTR libInterfaces[] =
476 (CONST_APTR)lib_managerTags,
477 (CONST_APTR)mainTags,
478 (CONST_APTR)NULL
481 // Our libraries always have to carry a 68k jump table with it, so
482 // lets define it here as extern, as we are going to link it to
483 // our binary here.
484 #ifndef NO_VECTABLE68K
485 extern CONST APTR VecTable68K[];
486 #endif
488 STATIC CONST struct TagItem libCreateTags[] =
490 { CLT_DataSize, sizeof(struct LibraryHeader) },
491 { CLT_InitFunc, (Tag)LibInit },
492 { CLT_Interfaces, (Tag)libInterfaces },
493 #ifndef NO_VECTABLE68K
494 { CLT_Vector68K, (Tag)VecTable68K },
495 #endif
496 { TAG_DONE, 0 }
499 #else
501 STATIC CONST CONST_APTR LibVectors[] =
503 #ifdef __MORPHOS__
504 (CONST_APTR)FUNCARRAY_32BIT_NATIVE,
505 #endif
506 #ifndef __AROS__
507 (CONST_APTR)LibOpen,
508 (CONST_APTR)LibClose,
509 (CONST_APTR)LibExpunge,
510 (CONST_APTR)LibNull,
511 (CONST_APTR)MCC_Query,
512 #else
513 #ifdef AROS_ABI_V1
514 (CONST_APTR)AROS_SLIB_ENTRY(LibOpen, __MCC_, 1),
515 (CONST_APTR)AROS_SLIB_ENTRY(LibClose, __MCC_, 2),
516 (CONST_APTR)AROS_SLIB_ENTRY(LibExpunge, __MCC_, 3),
517 (CONST_APTR)LibNull,
518 (CONST_APTR)AROS_SLIB_ENTRY(MCC_Query, __MCC_, 5),
519 #else
520 (CONST_APTR)AROS_SLIB_ENTRY(LibOpen, __MCC_),
521 (CONST_APTR)AROS_SLIB_ENTRY(LibClose, __MCC_),
522 (CONST_APTR)AROS_SLIB_ENTRY(LibExpunge, __MCC_),
523 (CONST_APTR)LibNull,
524 (CONST_APTR)AROS_SLIB_ENTRY(MCC_Query, __MCC_),
525 #endif
526 #endif
527 (CONST_APTR)-1
530 STATIC CONST IPTR LibInitTab[] =
532 sizeof(struct LibraryHeader),
533 (IPTR)LibVectors,
534 (IPTR)NULL,
535 (IPTR)LibInit
538 #endif
540 /* ------------------- ROM Tag ------------------------ */
541 STATIC const USED_VAR struct Resident ROMTag =
543 RTC_MATCHWORD,
544 (struct Resident *)&ROMTag,
545 (struct Resident *)(&ROMTag + 1),
546 #if defined(__amigaos4__)
547 RTF_AUTOINIT|RTF_NATIVE, // The Library should be set up according to the given table.
548 #elif defined(__MORPHOS__)
549 RTF_AUTOINIT|RTF_EXTENDED|RTF_PPC,
550 #elif defined(__AROS__)
551 RTF_AUTOINIT|RTF_EXTENDED,
552 #else
553 RTF_AUTOINIT,
554 #endif
555 VERSION,
556 NT_LIBRARY,
558 (char *)UserLibName,
559 (char *)UserLibID+6, // +6 to skip '$VER: '
560 #if defined(__amigaos4__)
561 (APTR)libCreateTags, // This table is for initializing the Library.
562 #else
563 (APTR)LibInitTab,
564 #endif
565 #if defined(__MORPHOS__) || defined(__AROS__)
566 REVISION,
568 #endif
571 #if defined(__MORPHOS__)
573 * To tell the loader that this is a new emulppc elf and not
574 * one for the ppc.library.
575 * ** IMPORTANT **
577 const USED_VAR ULONG __abox__ = 1;
579 #endif /* __MORPHOS__ */
581 /****************************************************************************/
582 /* Stack enforcing function which allows to make sure that a function has */
583 /* enough stack space during its execution time */
584 /****************************************************************************/
586 #if defined(MIN_STACKSIZE) && !defined(__amigaos4__)
588 /* generic StackSwap() function which calls function() surrounded by
589 StackSwap() calls */
590 #if defined(__AROS__)
591 ULONG stackswap_call(struct StackSwapStruct *stack,
592 ULONG (*function)(struct LibraryHeader *),
593 struct LibraryHeader *arg)
595 struct StackSwapArgs swapargs;
597 swapargs.Args[0] = (IPTR)arg;
599 return NewStackSwap(stack, function, &swapargs);
601 #elif defined(__MORPHOS__)
602 ULONG stackswap_call(struct StackSwapStruct *stack,
603 ULONG (*function)(struct LibraryHeader *),
604 struct LibraryHeader *arg)
606 struct PPCStackSwapArgs swapargs;
608 swapargs.Args[0] = (ULONG)arg;
610 return NewPPCStackSwap(stack, function, &swapargs);
612 #elif defined(__mc68000__)
613 ULONG stackswap_call(struct StackSwapStruct *stack,
614 ULONG (*function)(struct LibraryHeader *),
615 struct LibraryHeader *arg);
617 asm(".text \n\
618 .even \n\
619 .globl _stackswap_call \n\
620 _stackswap_call: \n\
621 moveml #0x3022,sp@- \n\
622 movel sp@(20),d3 \n\
623 movel sp@(24),a2 \n\
624 movel sp@(28),d2 \n\
625 movel _SysBase,a6 \n\
626 movel d3,a0 \n\
627 jsr a6@(-732:W) \n\
628 movel d2,sp@- \n\
629 jbsr a2@ \n\
630 movel d0,d2 \n\
631 addql #4,sp \n\
632 movel _SysBase,a6 \n\
633 movel d3,a0 \n\
634 jsr a6@(-732:W) \n\
635 movel d2,d0 \n\
636 moveml sp@+,#0x440c \n\
637 rts");
638 #else
639 #error Bogus operating system
640 #endif
642 STATIC BOOL callMccFunction(ULONG (*function)(struct LibraryHeader *), struct LibraryHeader *arg)
644 BOOL success = FALSE;
645 struct Task *tc;
646 ULONG stacksize;
648 // retrieve the task structure for the
649 // current task
650 tc = FindTask(NULL);
652 #if defined(__MORPHOS__)
653 // In MorphOS we have two stacks. One for PPC code and another for 68k code.
654 // We are only interested in the PPC stack.
655 NewGetTaskAttrsA(tc, &stacksize, sizeof(ULONG), TASKINFOTYPE_STACKSIZE, NULL);
656 #else
657 // on all other systems we query via SPUpper-SPLower calculation
658 stacksize = (IPTR)tc->tc_SPUpper - (IPTR)tc->tc_SPLower;
659 #endif
661 // Swap stacks only if current stack is insufficient
662 if(stacksize < MIN_STACKSIZE)
664 struct StackSwapStruct *stack;
666 if((stack = AllocVec(sizeof(*stack), MEMF_PUBLIC)) != NULL)
668 if((stack->stk_Lower = AllocVec(MIN_STACKSIZE, MEMF_PUBLIC)) != NULL)
670 // perform the StackSwap
671 #if defined(__AROS__)
672 // AROS uses an APTR type for stk_Upper
673 stack->stk_Upper = (APTR)((IPTR)stack->stk_Lower + MIN_STACKSIZE);
674 #else
675 // all other systems use ULONG
676 stack->stk_Upper = (ULONG)stack->stk_Lower + MIN_STACKSIZE;
677 #endif
678 stack->stk_Pointer = (APTR)stack->stk_Upper;
680 // call routine but with embedding it into a [NewPPC]StackSwap()
681 success = stackswap_call(stack, function, arg);
683 FreeVec(stack->stk_Lower);
685 FreeVec(stack);
688 else
689 success = function(arg);
691 return success;
693 #else // MIN_STACKSIZE && __amigaos4__
694 #define callMccFunction(func, arg) func(arg)
695 #endif // MIN_STACKSIZE && __amigaos4__
697 /******************************************************************************/
698 /* Wrapper functions to perform certain tasks in our LibInit/LibOpen etc. */
699 /******************************************************************************/
701 /* open and init all necessary library and stuff in the LibInit() phase */
702 STATIC ULONG mccLibInit(struct LibraryHeader *base)
704 // now that this library/class is going to be initialized for the first time
705 // we go and open all necessary libraries on our own
706 #if defined(__amigaos4__)
707 if((DOSBase = OpenLibrary("dos.library", 39)) &&
708 GETINTERFACE(IDOS, struct DOSIFace *, DOSBase))
709 if((GfxBase = OpenLibrary("graphics.library", 39)) &&
710 GETINTERFACE(IGraphics, struct GraphicsIFace *, GfxBase))
711 if((IntuitionBase = OpenLibrary("intuition.library", 39)) &&
712 GETINTERFACE(IIntuition, struct IntuitionIFace *, IntuitionBase))
713 if((UtilityBase = OpenLibrary("utility.library", 39)) &&
714 GETINTERFACE(IUtility, struct UtilityIFace *, UtilityBase))
715 #else
716 if((DOSBase = (struct DosLibrary*)OpenLibrary("dos.library", 39)) &&
717 (GfxBase = (struct GfxBase*)OpenLibrary("graphics.library", 39)) &&
718 (IntuitionBase = (struct IntuitionBase*)OpenLibrary("intuition.library", 39)) &&
719 (UtilityBase = (APTR)OpenLibrary("utility.library", 39)))
720 #endif
722 // we have to please the internal utilitybase
723 // pointers of libnix and clib2
724 #if !defined(__NEWLIB__)
725 __UtilityBase = (APTR)UtilityBase;
726 #if defined(__amigaos4__)
727 __IUtility = IUtility;
728 #endif
729 #endif
731 #if defined(DEBUG)
732 SetupDebug();
733 #endif
735 if((MUIMasterBase = OpenLibrary(MUIMASTER_NAME, MASTERVERSION)) &&
736 GETINTERFACE(IMUIMaster, struct MUIMasterIFace*, MUIMasterBase))
738 #if defined(PRECLASSINIT)
739 if(PreClassInit())
740 #endif
742 #ifdef SUPERCLASS
743 ThisClass = MUI_CreateCustomClass(&base->lh_Library, (STRPTR)SUPERCLASS, NULL, sizeof(struct INSTDATA), ENTRY(_Dispatcher));
744 if(ThisClass)
745 #endif
747 #ifdef SUPERCLASSP
748 if((ThisClassP = MUI_CreateCustomClass(&base->lh_Library, (STRPTR)SUPERCLASSP, NULL, sizeof(struct INSTDATAP), ENTRY(_DispatcherP))))
749 #endif
751 #ifdef SUPERCLASS
752 #define THISCLASS ThisClass
753 #else
754 #define THISCLASS ThisClassP
755 #endif
757 // in case the user defined an own ClassInit()
758 // function we call it protected by a semaphore as
759 // this user may be stupid and break the Forbid() state
760 // of LibInit()
761 #if defined(CLASSINIT)
762 if(ClassInit(&base->lh_Library))
763 #endif
765 // everything was successfully so lets
766 // make sure we return TRUE
767 return TRUE;
769 #if defined(CLASSINIT)
770 else
771 E(DBF_STARTUP, "ClassInit(%s) failed", CLASS);
772 #endif
774 // if we pass this point than an error
775 // occurred and we have to cleanup
776 #if defined(SUPERCLASSP)
777 MUI_DeleteCustomClass(ThisClassP);
778 ThisClassP = NULL;
779 #endif
782 #if defined(SUPERCLASS)
783 MUI_DeleteCustomClass(ThisClass);
784 ThisClass = NULL;
785 #endif
789 DROPINTERFACE(IMUIMaster);
790 CloseLibrary(MUIMasterBase);
791 MUIMasterBase = NULL;
794 DROPINTERFACE(IUtility);
795 CloseLibrary((struct Library *)UtilityBase);
796 UtilityBase = NULL;
799 if(IntuitionBase)
801 DROPINTERFACE(IIntuition);
802 CloseLibrary((struct Library *)IntuitionBase);
803 IntuitionBase = NULL;
806 if(GfxBase)
808 DROPINTERFACE(IGraphics);
809 CloseLibrary((struct Library *)GfxBase);
810 GfxBase = NULL;
813 if(DOSBase)
815 DROPINTERFACE(IDOS);
816 CloseLibrary((struct Library *)DOSBase);
817 DOSBase = NULL;
820 E(DBF_STARTUP, "mccLibInit(%s) failed", CLASS);
821 return FALSE;
824 /* expunge everything we previously opened and call user definable functions */
825 STATIC ULONG mccLibExpunge(UNUSED struct LibraryHeader *base)
827 // in case the user specified that he has an own class
828 // expunge function we call it right here, not caring about
829 // any return value.
830 #if defined(CLASSEXPUNGE)
831 ClassExpunge(&base->lh_Library);
832 #endif
834 // now we remove our own stuff here step-by-step
835 #ifdef SUPERCLASSP
836 if(ThisClassP)
838 MUI_DeleteCustomClass(ThisClassP);
839 ThisClassP = NULL;
841 #endif
843 #ifdef SUPERCLASS
844 if(ThisClass)
846 MUI_DeleteCustomClass(ThisClass);
847 ThisClass = NULL;
849 #endif
851 // we inform the user that all main class expunge stuff
852 // is finished, if he want's to get informed.
853 #if defined(POSTCLASSEXPUNGE)
854 PostClassExpunge();
855 #endif
857 #if defined(DEBUG)
858 CleanupDebug();
859 #endif
861 // cleanup the various library bases and such
862 if(MUIMasterBase)
864 DROPINTERFACE(IMUIMaster);
865 CloseLibrary(MUIMasterBase);
866 MUIMasterBase = NULL;
869 if(UtilityBase)
871 DROPINTERFACE(IUtility);
872 CloseLibrary((struct Library *)UtilityBase);
873 UtilityBase = NULL;
876 if(IntuitionBase)
878 DROPINTERFACE(IIntuition);
879 CloseLibrary((struct Library *)IntuitionBase);
880 IntuitionBase = NULL;
883 if(GfxBase)
885 DROPINTERFACE(IGraphics);
886 CloseLibrary((struct Library *)GfxBase);
887 GfxBase = NULL;
890 if(DOSBase)
892 DROPINTERFACE(IDOS);
893 CloseLibrary((struct Library *)DOSBase);
894 DOSBase = NULL;
897 return TRUE;
900 /* we call the user definable function here only */
901 #if defined(CLASSOPEN)
902 STATIC ULONG mccLibOpen(struct LibraryHeader *base)
904 return ClassOpen(&base->lh_Library);
906 #endif
908 /* we call the user definable function here only */
909 #if defined(CLASSCLOSE)
910 STATIC ULONG mccLibClose(struct LibraryHeader *base)
912 ClassClose(&base->lh_Library);
913 return TRUE;
915 #endif
917 /******************************************************************************/
918 /* Standard Library Functions, all of them are called in Forbid() state. */
919 /******************************************************************************/
921 #if defined(__amigaos4__)
922 STATIC struct LibraryHeader * LibInit(struct LibraryHeader *base, BPTR librarySegment, struct ExecIFace *pIExec)
924 struct Library *sb = (struct Library *)pIExec->Data.LibBase;
925 IExec = pIExec;
926 #elif defined(__MORPHOS__)
927 STATIC struct LibraryHeader * LibInit(struct LibraryHeader *base, BPTR librarySegment, struct ExecBase *sb)
929 #elif defined(__AROS__)
930 AROS_UFH3 (struct LibraryHeader *, LibInit,
931 AROS_UFHA(struct LibraryHeader *, base, D0),
932 AROS_UFHA(BPTR, librarySegment, A0),
933 AROS_UFHA(struct ExecBase *, sb, A6)
936 AROS_USERFUNC_INIT
937 #else
938 STATIC struct LibraryHeader * LIBFUNC LibInit(REG(d0, struct LibraryHeader *base), REG(a0, BPTR librarySegment), REG(a6, struct ExecBase *sb))
940 #endif
942 SysBase = sb;
944 // make sure that this is really a 68020+ machine if optimized for 020+
945 #if _M68060 || _M68040 || _M68030 || _M68020 || __mc68020 || __mc68030 || __mc68040 || __mc68060
946 if(!(SysBase->AttnFlags & AFF_68020))
947 return(NULL);
948 #endif
950 #if defined(__amigaos4__) && defined(__NEWLIB__)
951 if((NewlibBase = OpenLibrary("newlib.library", 3)) &&
952 GETINTERFACE(INewlib, struct Interface*, NewlibBase))
953 #endif
955 BOOL success = FALSE;
957 D(DBF_STARTUP, "LibInit(" CLASS ")");
959 // cleanup the library header structure beginning with the
960 // library base, even if that is done automcatically, we explicitly
961 // do it here for consistency reasons.
962 base->lh_Library.lib_Node.ln_Type = NT_LIBRARY;
963 base->lh_Library.lib_Node.ln_Pri = 0;
964 base->lh_Library.lib_Node.ln_Name = (char *)UserLibName;
965 base->lh_Library.lib_Flags = LIBF_CHANGED | LIBF_SUMUSED;
966 base->lh_Library.lib_IdString = (char *)UserLibID; // here without +6 or otherwise MUI doesn't identify it.
967 base->lh_Library.lib_Version = VERSION;
968 base->lh_Library.lib_Revision = REVISION;
970 // init our protecting semaphore and the
971 // initialized flag variable
972 memset(&base->lh_Semaphore, 0, sizeof(base->lh_Semaphore));
973 InitSemaphore(&base->lh_Semaphore);
975 // protect mccLibInit()
976 ObtainSemaphore(&base->lh_Semaphore);
978 // If we are not running on AmigaOS4 (no stackswap required) we go and
979 // do an explicit StackSwap() in case the user wants to make sure we
980 // have enough stack for his user functions
981 success = callMccFunction(mccLibInit, base);
983 // unprotect
984 ReleaseSemaphore(&base->lh_Semaphore);
986 // check if everything worked out fine
987 if(success == TRUE)
989 // everything was successfully so lets
990 // set the initialized value and contiue
991 // with the class open phase
992 base->lh_Segment = librarySegment;
994 // return the library base as success
995 return base;
998 #if defined(__amigaos4__) && defined(__NEWLIB__)
999 if(NewlibBase)
1001 DROPINTERFACE(INewlib);
1002 CloseLibrary(NewlibBase);
1003 NewlibBase = NULL;
1005 #endif
1008 return(NULL);
1009 #ifdef __AROS__
1010 AROS_USERFUNC_EXIT
1011 #endif
1014 /*****************************************************************************************************/
1015 /*****************************************************************************************************/
1017 #ifndef __amigaos4__
1018 #define DeleteLibrary(LIB) \
1019 FreeMem((STRPTR)(LIB)-(LIB)->lib_NegSize, (ULONG)((LIB)->lib_NegSize+(LIB)->lib_PosSize))
1020 #endif
1022 STATIC BPTR LibDelete(struct LibraryHeader *base)
1024 #if defined(__amigaos4__)
1025 struct ExecIFace *IExec = (struct ExecIFace *)(*(struct ExecBase **)4)->MainInterface;
1026 #endif
1027 BPTR rc;
1029 // remove the library base from exec's lib list in advance
1030 Remove((struct Node *)base);
1032 // protect mccLibExpunge()
1033 ObtainSemaphore(&base->lh_Semaphore);
1035 // make sure we have enough stack here
1036 callMccFunction(mccLibExpunge, base);
1038 // unprotect
1039 ReleaseSemaphore(&base->lh_Semaphore);
1041 #if defined(__amigaos4__) && defined(__NEWLIB__)
1042 if(NewlibBase)
1044 DROPINTERFACE(INewlib);
1045 CloseLibrary(NewlibBase);
1046 NewlibBase = NULL;
1048 #endif
1050 // make sure the system deletes the library as well.
1051 rc = base->lh_Segment;
1052 DeleteLibrary(&base->lh_Library);
1054 return rc;
1057 #if defined(__amigaos4__)
1058 STATIC BPTR LibExpunge(struct LibraryManagerInterface *Self)
1060 struct LibraryHeader *base = (struct LibraryHeader *)Self->Data.LibBase;
1061 #elif defined(__MORPHOS__)
1062 STATIC BPTR LibExpunge(void)
1064 struct LibraryHeader *base = (struct LibraryHeader *)REG_A6;
1065 #elif defined(__AROS__)
1066 AROS_LH1 (BPTR, LibExpunge,
1067 AROS_LHA(UNUSED struct LibraryHeader *, extralh, D0),
1068 struct LibraryHeader *, base, 3, __MCC_
1071 AROS_LIBFUNC_INIT
1072 #else
1073 STATIC BPTR LIBFUNC LibExpunge(REG(a6, struct LibraryHeader *base))
1075 #endif
1076 BPTR rc;
1078 D(DBF_STARTUP, "LibExpunge(" CLASS "): %ld", base->lh_Library.lib_OpenCnt);
1080 // in case our open counter is still > 0, we have
1081 // to set the late expunge flag and return immediately
1082 if(base->lh_Library.lib_OpenCnt > 0)
1084 base->lh_Library.lib_Flags |= LIBF_DELEXP;
1085 rc = 0;
1087 else
1089 rc = LibDelete(base);
1092 return(rc);
1093 #ifdef __AROS__
1094 AROS_LIBFUNC_EXIT
1095 #endif
1098 /*****************************************************************************************************/
1099 /*****************************************************************************************************/
1101 #if defined(__amigaos4__)
1102 STATIC struct LibraryHeader *LibOpen(struct LibraryManagerInterface *Self, ULONG version UNUSED)
1104 struct LibraryHeader *base = (struct LibraryHeader *)Self->Data.LibBase;
1105 #elif defined(__MORPHOS__)
1106 STATIC struct LibraryHeader *LibOpen(void)
1108 struct LibraryHeader *base = (struct LibraryHeader *)REG_A6;
1109 #elif defined(__AROS__)
1110 AROS_LH1 (struct LibraryHeader *, LibOpen,
1111 AROS_LHA (UNUSED ULONG, version, D0),
1112 struct LibraryHeader *, base, 1, __MCC_
1115 AROS_LIBFUNC_INIT
1116 #else
1117 STATIC struct LibraryHeader * LIBFUNC LibOpen(REG(d0, UNUSED ULONG version), REG(a6, struct LibraryHeader *base))
1119 #endif
1120 struct LibraryHeader *res = NULL;
1122 D(DBF_STARTUP, "LibOpen(" CLASS "): %ld", base->lh_Library.lib_OpenCnt);
1124 // LibOpen(), LibClose() and LibExpunge() are called while the system is in
1125 // Forbid() state. That means that these functions should be quick and should
1126 // not break this Forbid()!! Therefore the open counter should be increased
1127 // as the very first instruction during LibOpen(), because a ClassOpen()
1128 // which breaks a Forbid() and another task calling LibExpunge() will cause
1129 // to expunge this library while it is not yet fully initialized. A crash
1130 // is unavoidable then. Even the semaphore does not guarantee 100% protection
1131 // against such a race condition, because waiting for the semaphore to be
1132 // obtained will effectively break the Forbid()!
1134 // increase the open counter ahead of anything else
1135 base->lh_Library.lib_OpenCnt++;
1137 // delete the late expunge flag
1138 base->lh_Library.lib_Flags &= ~LIBF_DELEXP;
1140 // check if the user defined a ClassOpen() function
1141 #if defined(CLASSOPEN)
1143 struct ExecIFace *IExec = (struct ExecIFace *)(*(struct ExecBase **)4)->MainInterface;
1144 BOOL success = FALSE;
1146 // protect
1147 ObtainSemaphore(&base->lh_Semaphore);
1149 // make sure we have enough stack here
1150 success = callMccFunction(mccLibOpen, base);
1152 // here we call the user-specific function for LibOpen() where
1153 // he can do whatever he wants because of the semaphore protection.
1154 if(success == TRUE)
1155 res = base;
1156 else
1158 E(DBF_STARTUP, "ClassOpen(" CLASS ") failed");
1160 // decrease the open counter again
1161 base->lh_Library.lib_OpenCnt--;
1164 // release the semaphore
1165 ReleaseSemaphore(&base->lh_Semaphore);
1167 #else
1168 res = base;
1169 #endif
1171 return res;
1172 #ifdef __AROS__
1173 AROS_LIBFUNC_EXIT
1174 #endif
1177 /*****************************************************************************************************/
1178 /*****************************************************************************************************/
1180 #if defined(__amigaos4__)
1181 STATIC BPTR LibClose(struct LibraryManagerInterface *Self)
1183 struct LibraryHeader *base = (struct LibraryHeader *)Self->Data.LibBase;
1184 #elif defined(__MORPHOS__)
1185 STATIC BPTR LibClose(void)
1187 struct LibraryHeader *base = (struct LibraryHeader *)REG_A6;
1188 #elif defined(__AROS__)
1189 AROS_LH0 (BPTR, LibClose,
1190 struct LibraryHeader *, base, 2, __MCC_
1193 AROS_LIBFUNC_INIT
1194 #else
1195 STATIC BPTR LIBFUNC LibClose(REG(a6, struct LibraryHeader *base))
1197 #endif
1198 BPTR rc = 0;
1200 D(DBF_STARTUP, "LibClose(" CLASS "): %ld", base->lh_Library.lib_OpenCnt);
1202 // check if the user defined a ClassClose() function
1203 #if defined(CLASSCLOSE)
1205 struct ExecIFace *IExec = (struct ExecIFace *)(*(struct ExecBase **)4)->MainInterface;
1207 // protect
1208 ObtainSemaphore(&base->lh_Semaphore);
1210 // make sure we have enough stack here
1211 success = callMccFunction(mccLibClose, base);
1213 // release the semaphore
1214 ReleaseSemaphore(&base->lh_Semaphore);
1216 #endif
1218 // decrease the open counter
1219 base->lh_Library.lib_OpenCnt--;
1221 // in case the opern counter is <= 0 we can
1222 // make sure that we free everything
1223 if(base->lh_Library.lib_OpenCnt <= 0)
1225 // in case the late expunge flag is set we go and
1226 // expunge the library base right now
1227 if(base->lh_Library.lib_Flags & LIBF_DELEXP)
1229 rc = LibDelete(base);
1233 return rc;
1234 #ifdef __AROS__
1235 AROS_LIBFUNC_EXIT
1236 #endif
1239 /*****************************************************************************************************/
1240 /*****************************************************************************************************/
1242 #if defined(__amigaos4__)
1243 STATIC IPTR LIBFUNC MCC_Query(UNUSED struct Interface *self, REG(d0, LONG which))
1245 #elif defined(__MORPHOS__)
1246 STATIC IPTR MCC_Query(void)
1248 LONG which = (LONG)REG_D0;
1249 #elif defined(__AROS__)
1250 AROS_LH1(IPTR, MCC_Query,
1251 AROS_LHA(LONG, which, D0),
1252 UNUSED struct LibraryHeader *, base, 5, __MCC_
1255 AROS_LIBFUNC_INIT
1256 #else
1257 STATIC IPTR LIBFUNC MCC_Query(REG(d0, LONG which))
1259 #endif
1261 D(DBF_STARTUP, "MCC_Query(" CLASS "): %ld", which);
1263 switch (which)
1265 #ifdef SUPERCLASS
1266 case 0: return((IPTR)ThisClass);
1267 #endif
1269 #ifdef SUPERCLASSP
1270 case 1: return((IPTR)ThisClassP);
1271 #endif
1273 #ifdef PREFSIMAGEOBJECT
1274 case 2:
1276 Object *obj = PREFSIMAGEOBJECT;
1277 return((IPTR)obj);
1279 #endif
1281 #ifdef ONLYGLOBAL
1282 case 3:
1284 return(TRUE);
1286 #endif
1288 #ifdef INFOCLASS
1289 case 4:
1291 return(TRUE);
1293 #endif
1295 #ifdef USEDCLASSES
1296 case 5:
1298 return((IPTR)USEDCLASSES);
1300 #endif
1302 #ifdef USEDCLASSESP
1303 case 6:
1305 return((IPTR)USEDCLASSESP);
1307 #endif
1309 #ifdef SHORTHELP
1310 case 7:
1312 return((IPTR)SHORTHELP);
1314 #endif
1317 return(0);
1318 #ifdef __AROS__
1319 AROS_LIBFUNC_EXIT
1320 #endif
1323 #ifdef __cplusplus
1325 #endif