/*
 * Mesa 3-D graphics library MacOS Driver
 * Version:  3.2
 *
 * Copyright (C) 1999  Mikl—s Fazekas   All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
/*
 *	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);
}
