/* MuiClassHeader.c Universal header file MUI custom classes V1.0 Copyright(C) 1994 Jochen Wiedmann Computer: Amiga 1200 Compiler: Dice 3.01 Author: Jochen Wiedmann Am Eisteich 9 72555 Metzingen Germany Phone: 07123 / 14881 Internet: wiedmann@zdv.uni-tuebingen.de This code implements the usual startup code of a MUI custom class. I recommend reading Appendix C (Sample Library Source Code) of the RKM: Libraries, Third Edition for a complete understanding of the following. Another good choice would be the shared library example of the Dice distribution. Your library should be implmented in another file. You must define the following preprocessor symbols with compiler options, when this file is compiled: LIBNAME: Name of this library, "chess.library" for example LIBVERSION: Library version, "40" for example LIBREVISION: Library revision, "1" for example LIBINITFUNC: The name of the initialization function. Will be called with the library base pointer in register a6, should return 0 for success, nonzero otherwise. LIBTERMFUNC: The name of a function called when the class will be removed from the system; will receive the library base pointer in register a6. The following preprocessor symbols may be defined, but don't need to: LIBOPENFUNC: Function to be called every time the library is opened. Does not make much sense in most cases. (Default is no library specific stuff.) LIBCLOSEFUNC: Function to be called every time when CloseLibrary() is executed. This is the opponent to LIBCLOSEFUNC and does not make much sense in most cases either. (Default is no library specific stuff.) LIBBASESIZE: Size of the library base, "sizeof(struct Library)" for example. (This is the default, if LIBBASESIZE isn't defined. WARNINGS - WARNINGS - WARNINGS - WARNINGS - WARNINGS - WARNINGS - WARNINGS - This code depends heavily on some assumptions which are fulfilled by Dice: * All data declared as "const" will go to the code segment * The compiler doesn't rearrange the order of the data and code items. - You may use uninialized data items in your library code. However, the startup code will *not* clear the BSS segment. This means that you must not depend on an uninitialized variable being zero! - You may use the data and bss segment as usual. But remember that this data will be global to the library and hence shared by all users of the library. And don't forget to recreate the a4 register, if you use such data items! (Usually by adding __saveds or something similar to your functions.) EXAMPLE: To create the header of "userdata.mcc", version 40.1 with library specific routines InitUserdata and TermUserdata, and a "struct UserdataBase" as library base you would do the following: dcc -DLIBNAME=userdata.mcc -DLIBVERSION=40 -DLIBREVISION=1 -DLIBINITFUNC=InitUserdata -DLIBTERMFUNC=TermUserdata "-DLIBBASESIZE=sizeof(struct UserdataBase)" -c Userdata.c */ /**************************************************************************** Include files ****************************************************************************/ #ifndef EXEC_TYPES_H #include #endif #ifndef EXEC_NODES_H #include #endif #ifndef EXEC_RESIDENT_H #include #endif #ifndef EXEC_LIBRARIES_H #include #endif #ifndef EXEC_INITIALIZERS_H #include #endif #ifndef DOS_DOS_H #include #endif #ifndef CLIB_EXEC_PROTOS_H #include #endif #ifndef PRAGMAS_EXEC_PRAGMAS_H #include #endif /***************************************************************************** Compiler specific stuff (Handling register arguments) *****************************************************************************/ #if defined(_DCC) #define REG(x) __ ## x #define SAVEDS __geta4 #define ASM #define REGARGS __regargs #else #if defined(__SASC) #define REG(x) register __ ## x #define SAVEDS __saveds #define ASM __asm #define REGARGS __regargs #else #error "Don't know how to handle register arguments for your compiler." #endif #endif /* This routine is an entry point if anyone might wish to run the library as an executable. */ STATIC LONG DummyStart(VOID){return(-1);} /**************************************************************************** Library name, ID and version string ****************************************************************************/ #define S(x) #x const STATIC UBYTE LibName [] = S(LIBNAME); const STATIC UBYTE IdString [] = S(LIBNAME) " " S(LIBVERSION) "." \ S(LIBREVISION) " (" __DATE__ ")\r\n"; extern const UBYTE VersionTag []; /***************************************************************************** The following table is used to initialize the library base. See exec.library/InitStruct() and "exec/initializers.i" for details. *****************************************************************************/ const STATIC UWORD DataTable[] = { 0xa000 + (int) OFFSET(Node, ln_Type), NT_LIBRARY << 8, 0x8000 + (int) OFFSET(Node, ln_Name) }; const STATIC ULONG DataTable1[] = { (ULONG) LibName }; const STATIC UWORD DataTable2[] = { 0xa000 + (int) OFFSET(Library, lib_Flags), (LIBF_SUMUSED|LIBF_CHANGED) << 8, 0x9000 + (int) OFFSET(Library, lib_Version), LIBVERSION, 0x9000 + (int) OFFSET(Library, lib_Revision), LIBREVISION, 0x8000 + (int) OFFSET(Library, lib_IdString) }; const STATIC ULONG DataTable3[] = { (ULONG) IdString, 0 }; /**************************************************************************** The following table is expected to be at the beginning of any library. ****************************************************************************/ extern APTR InitTable []; const STATIC struct Resident RomTag = { RTC_MATCHWORD, /* ILLEGAL instruction, magic cookie to identify Resident structure */ &RomTag, /* Additional legality check */ &RomTag, /* Where to continue looking for Resident structures */ RTF_AUTOINIT, /* Easy initialization */ LIBVERSION, /* Library version */ NT_LIBRARY, /* type of module */ 0, /* Priority, don't use */ LibName, /* library name */ IdString, /* Id string */ InitTable /* See below */ }; /***************************************************************************** The following function will be called at startup. Inputs: LibPtr - pointer to the library base, initialized due to the specifications in DataTable SegList - BPTR to the segment list _SysBase - the usual ExecBase pointer Result: LibPtr, if all was okay and the library may be linked into the system library list. NULL otherwise *****************************************************************************/ STATIC BPTR MySegList; SAVEDS ASM struct Library *_LibInit(REG(d0) struct Library *LibPtr, REG(a0) BPTR SegList, REG(a6) struct ExecBase *_SysBase) { extern ULONG LIBINITFUNC(REG(a6) struct Library *); MySegList = SegList; if (LIBINITFUNC(LibPtr)) { return((BPTR) NULL); } return(LibPtr); } /**************************************************************************** The following functions are called from exec.library/OpenLibrary(), exec.library/CloseLibrary() and exec.library/ExpungeLibrary(), respectively. Exec puts the library base pointer in a6 and turns off task switching while they are executed, so we should not wait too long inside. ****************************************************************************/ /* This function is called from exec.library/OpenLibrary(). Inputs: LibPtr - pointer to the library base Version - the suggested version number Result: LibPtr, if successful, NULL otherwise */ ASM struct Library *_LibOpen(REG(a6) struct Library *LibPtr, REG(d0) ULONG Version) { #ifdef LIBOPENFUNC extern ULONG LIBOPENFUNC(REG(a6) struct Library *); #endif ++LibPtr->lib_OpenCnt; LibPtr->lib_Flags &= ~LIBF_DELEXP; /* Prevent delayed expunge */ /* Library specific initialization */ #ifdef LIBOPENFUNC extern ULONG LIBOPENFUNC(LibPtr); #endif return(LibPtr); } /* This function is called from exec.library/RemoveLibrary(). Inputs: LibPtr - pointer to the library base. Result: Segment list of the library (see arguments of _LibInit()), if the library isn't opened currently, NULL otherwise. */ extern struct Library *SysBase; SAVEDS ASM BPTR _LibExpunge(REG(a6) struct Library *LibPtr) { extern VOID LIBTERMFUNC(REG(a6) struct Library *); if (LibPtr->lib_OpenCnt) { LibPtr->lib_Flags |= LIBF_DELEXP; return((BPTR) NULL); } /* Library specific cleanup. */ LIBTERMFUNC(LibPtr); /* Remove the library from the library list. */ Remove((struct Node *) LibPtr); return(MySegList); } /* This function is called from exec/CloseLibrary(). Inputs: LibPtr - pointer to the library base as returned from OpenLibrary(). Result: Segment list of the library (see arguments of _LibInit), if there was a delayed expunge and the library is no longer open, NULL otherwise. */ ASM BPTR _LibClose(REG(a6) struct Library *LibPtr) { #ifdef LIBCLOSEFUNC extern VOID LIBCLOSEFUNC(REG(a6) struct Library *); LIBCLOSEFUNC(LibPtr); #endif if (!(--LibPtr->lib_OpenCnt) && (LibPtr->lib_Flags & LIBF_DELEXP)) { return(_LibExpunge(LibPtr)); } return((BPTR) NULL); } /* Dummy function to return 0. */ ULONG _LibNull(VOID) { return(0); } /**************************************************************************** Table of functions included in this library; the first 4 are the same for any library and for internal use only, MCC_GetClass is the only public function of any MUI custom class. ****************************************************************************/ extern REGARGS VOID MCC_GetClass(VOID); const STATIC APTR LibFuncTable[] = { _LibOpen, _LibClose, _LibExpunge, _LibNull, MCC_GetClass, (APTR)-1 }; /**************************************************************************** The romtag specified that we were RTF_AUTOINIT. This means that rt_Init points to the table below. (Without RTF_AUTOINIT it would point to a routine to run.) ****************************************************************************/ #ifndef LIBBASESIZE #define LIBBASESIZE sizeof(struct Library) #endif const APTR InitTable[4] = { (APTR)LIBBASESIZE, /* size of library base */ (APTR)LibFuncTable, /* library function table */ (APTR)DataTable, /* library base initialization table */ (APTR)_LibInit, /* function to call on startup */ };