/*
 *	StartupSharedLib.c	-	init/startup/termination routines for Metrowerks C++ (PowerPC)
 *
 *	Copyright © 1995-1997 Metrowerks, Inc. All Rights Reserved.
 *
 *
 *	THEORY OF OPERATION
 *
 *	This version of the PPC startup code is intended to be used for shared library
 *	components of multi-fragment applications. It is designed to properly support
 *	exceptions thrown across fragment boundaries, and proper initialization and
 *	termination--including construction and destruction of static objects--for
 *	a shared library that is one component of a complex, multi-fragment program.
 *
 *	The startup file defines 2 entry-points:
 *
 *		__initialize	This must be the Initialization Entry-Point for the Application.
 *						__initialize() registers the exception-handling info for
 *						the application, and calls all static initializers.
 *
 *		__terminate		This must be the Termination Entry-Point for the Application
 *						__terminate() unregisters the exception-handling info for the
 *						shared application before the fragment is unloaded.
 *
 *	The new zero-runtime-overhead exception-handling mechanism requires that we
 *	keep track of all loaded fragments and their code/data section ranges--we
 *	cannot use the OS data structures to do this--so we must call routines which
 *	register and unregister the exception-handling info as a fragment is loaded/unloaded.
 *
 *	When the shared library is loaded, __sinit() will call constructors for static
 *	objects, linking them into the (per-application) global destructor chain. These
 *	objects will be destroyed when the application component of the program calls
 *	__destroy_global_chain() as part of its exit() handling. This will ensure the
 *	proper ordering of destruction wrt calling _atexit() handlers, cleaning up the
 *	I/O and console packages, etc.
 *
 *	This startup file must -not- be used for shared libraries with shared data sections,
 *	since these may be linked into multiple applications simultaneously, and cannot
 *	have its static objects linked into the application's global destructor chain.
 *
 */

#include <CodeFragments.h>
#include <Types.h>
#include <NMWException.h>
#include <Folders.h>

#include "mgliGetEnv.h"
#include "myalert.h"

	/*	external data	*/

extern char __code_start__[];				/*	(defined by linker)	*/
extern char	__code_end__[];					/*	(defined by linker)	*/
extern char __data_start__[];				/*	(defined by linker)	*/
extern char __data_end__[];					/*	(defined by linker)	*/
extern char __exception_table_start__[];	/*	(defined by linker)	*/
extern char __exception_table_end__[];		/*	(defined by linker)	*/
	/*	private data	*/

static int fragmentID;						/*	ID given to fragment by exception-handling	*/


	/*	prototypes	*/

#ifdef __cplusplus
extern "C" {
#endif

void __sinit(void);	/*	(generated by linker)	*/
pascal OSErr __initialize(const CFragInitBlock *theInitBlock);
pascal void __terminate(void);

#ifdef __cplusplus
}
#endif


/*
 *	__RTOC	-	return the TOC pointer for our code fragment
 *
 */

static asm char *__RTOC(void)
{
		mr		r3,RTOC
		blr
}

#define IsFileLocation(where) 	\
	(((where) == kDataForkCFragLocator)	||  \
	((where) == kResourceCFragLocator)	)

/*
 *	__initialize	-	Default initialization routine for Metrowerks C++ (PowerPC)
 *
 *	This routine should be specified as the PEF initialization routine in the container
 *	for any multi-fragment application.
 *
 */

pascal OSErr __initialize(const CFragInitBlock *theInitBlock)
{
#pragma unused (theInitBlock)

	/*	register this code fragment with the Exception Handling mechanism */
	fragmentID = __register_fragment(__code_start__, __code_end__,
									__data_start__, __data_end__,
									__exception_table_start__, __exception_table_end__,
									__RTOC());
	
	/*	call all static initializers */
	__sinit();
	
	/* Find out where we are, do not allow loading from extensions folder! */
	if (IsFileLocation(theInitBlock->fragLocator.where))
	{
		FSSpec fileSpec;
		SInt16	theVRef;
		SInt32	theDirID;
		OSErr	theErr;
		
		fileSpec = *(theInitBlock->fragLocator.u.onDisk.fileSpec);
		strcpy(&(fileSpec.name[1]),MGLI_CONFIG_FILE_NAME);
	    fileSpec.name[0] = strlen(MGLI_CONFIG_FILE_NAME);
		{
			
			theErr = FindFolder(kOnSystemDisk, kExtensionFolderType,
					false, &theVRef, &theDirID);
			if (theErr)
				return theErr;
			
			if (fileSpec.vRefNum == theVRef &&
			    fileSpec.parID == theDirID)
			{
				ShowStopAlert("Remove Mesa3DLibrary from extensions!",
				"Since the Mesa3DGraphics library can cause troubles with OpenGL applications, you shouldn't install into the extensions folder!\r Mesa should be stored in application folder! \r For more information go to: http://www.mesa3d.org/mac/!");
				return (OSErr)-1;
			}
		}
		
		if (!MCFG_readMesaConfigurationFileFromFSSpec(&fileSpec))
			MCFG_readMesaConfigurationFile(MGLI_CONFIG_FILE_NAME);
	}
	
	/*	return success to Code Fragment Manager */
	return(noErr);
}


/*
 *	__terminate	-	Default termination routine for Metrowerks C++ (PowerPC)
 *
 *	This routine should be specified as the PEF termination routine in the container
 *	for any multi-fragment application.
 *
 */

pascal void __terminate(void)
{
	//	unregister this code fragment with the Exception Handling mechanism
	__unregister_fragment(fragmentID);
}
