/* include this file if you need standard amiga command line parsing */
#ifdef __cplusplus
extern "C" {
#endif

#define timeval _timeval
#include <exec/types.h>
#include <exec/ports.h>
#include <exec/memory.h>
#include <exec/execbase.h>
#include <dos/dos.h>
#include <dos/dosextens.h>
#include <dos/exall.h>
#include <dos/rdargs.h>
#include <clib/alib_protos.h>
#include <graphics/gfxbase.h>
#include <inline/stubs.h>
#ifdef __OPTIMIZE__
#include <inline/exec.h>
#include <inline/dos.h>
#else
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#endif

void __destroy_argc_argv(void);
BOOL __build_argc_argv(int orig_d0, char *orig_a0, int *argc, char **argv[]);
static char *__MyGetProgramName(void);
int _X__main(int argc, char *argv[]);

struct Library *IconBase;
struct Library *CxBase;
struct Library *MathTransBase;
struct Library *MathBase;
struct Library *MathIeeeDoubBasBase;
struct Library *MathIeeeDoubTransBase;
struct Library *UtilityBase;

#ifdef stdin
#undef stdin
#endif
#ifdef stdout
#undef stdout
#endif
extern BPTR stdin;
extern BPTR stdout;

static struct RDArgs	*rda = NULL;	/* for CLI-startup */

static LONG **arguement_array=NULL;

static char *arguement_string=NULL;

void __destroy_argc_argv(void)
{
	/* Free all the space that was occupied by build_argc_argv */

	if(arguement_array)
	{
		if(arguement_array[0]) FreeVec(arguement_array[0]);
		FreeVec(arguement_array);
	}

		/* Free arguments passed by commandline allocated by ReadArgs() */

	if( rda )
	{
		FreeArgs( rda );
		FreeDosObject( DOS_RDARGS, rda );
	}

}

BOOL __build_argc_argv(int orig_d0, char *orig_a0, int *argc, char **argv[])
{
	/* We will store the name of our program in argv[0] */

	*argc=0;
    *argv=NULL;

	if(orig_d0)
	{
		/* start from CLI */
		/* parse arguements */

		/* here we have a return-terminated string in arguement_string,
           or nothing */

		if(arguement_string=orig_a0)
		{
#ifndef TEMPLATE
				int x;
		UBYTE *_template;
		UBYTE *s;
#endif
			/* Get memory for the arguement array */
#ifdef TEMPLATE_COUNT
			if( (arguement_array = (LONG **)AllocVec(sizeof(long)*(TEMPLATE_COUNT+2), MEMF_CLEAR)))
#else
			if( (arguement_array = (LONG **)AllocVec(sizeof(long)*110+100, MEMF_CLEAR)))
#endif
			{
					/* We have the memory */

				arguement_array[0]=(LONG *)__MyGetProgramName(); /* Programm-Name */

					/* Set up arguement template */

#ifndef TEMPLATE
				_template = (UBYTE *)&arguement_array[110];
				s=_template;

					/* give the program the chance of handling their own help */

				if(*orig_a0=='?')
				{
					arguement_array[1]=(LONG *)"?";	/* Options */

					*argc=2;
					*argv=(char **)arguement_array;

					return TRUE;
				}

					/* make 100 "," for template */

				for(x=0;x<99;x++) *s++=',';

#else
				UBYTE *_template=(UBYTE *)TEMPLATE;
#endif
					/* Do ReadArgs */

				if( (rda = (struct RDArgs *)AllocDosObject( DOS_RDARGS, NULL )))
				{
						/* Setup CSource */
#if 0
                    rda->RDA_Source.CS_Buffer = (UBYTE *)arguement_string;
                    rda->RDA_Source.CS_Length = orig_d0;
#endif
#ifdef TEMPLATE_HELP
					rda->RDA_ExtHelp = (UBYTE *) TEMPLATE_HELP;
#else
					rda->RDA_ExtHelp = NULL;
#endif
					if(ReadArgs( _template, (LONG *) &arguement_array[1], rda ) )
					{
						/* Args erfolgreich gelesen */

#ifndef TEMPLATE_COUNT
						/* Count args to store them in argc */

						int x=1;

						while( arguement_array[x] )
							x++;

						*argc=x;
#else
						*argc=TEMPLATE_COUNT+1;
#endif
						*argv=(char **)arguement_array;

					}
					else
					{
						/* ReadArgs error: give it to stdout */

						PrintFault(IoErr(), (UBYTE *)"");
						return FALSE;
					}
				}
				else
				{
					/* panic, we don't have the memory for RDArgs */
					return FALSE;
				}
			}
			else
			{
				/* panic, we don't have the memory for an arguement array */
				return FALSE;
			}
		}
		else
		{
			/* we have only to initialize argv[0]/[1] */

			if( (arguement_array = (LONG **)AllocVec(sizeof(long)*2, MEMF_CLEAR)))
			{
				arguement_array[0]=(LONG *)__MyGetProgramName(); /* Programm-Name */
				*argc    = 1;
				*argv    = (char **)arguement_array;
			}
			else
			{
				/* panic, we don't have enough memory ! */
				return FALSE;
			}

		}
	}
	else
	{
		/* Start from WB, do nearly nothing */

		*argc = 0;
		*argv = (char **)orig_a0;
	}

	return TRUE;
}


inline BOOL __OpenLibs(void)
{
	if(IconBase = OpenLibrary((STRPTR)"icon.library",37))
	{
		if(CxBase = OpenLibrary((STRPTR)"commodities.library",37))
		{
			if(MathBase = OpenLibrary((STRPTR)"mathffp.library",0L))
			{
				if(MathTransBase = OpenLibrary((STRPTR)"mathtrans.library",0L))
				{
					if(MathIeeeDoubTransBase = OpenLibrary((STRPTR)"mathieeedoubtrans.library",0L))
					{
						if(MathIeeeDoubBasBase = OpenLibrary((STRPTR)"mathieeedoubbas.library",0L))
						{
							if(UtilityBase = OpenLibrary((STRPTR)"utility.library",0L))
							{
								return TRUE;
							}
						}
					}
				}
			}
		}
	}

	return FALSE;
}



inline void __CloseLibs(void)
{
	struct Library *lib;

	if(MathBase) 				{ lib=(struct Library *)MathBase;				CloseLibrary(lib); }

	if(MathTransBase)			{ lib=(struct Library *)MathTransBase;	 		CloseLibrary(lib); }

	if(MathIeeeDoubBasBase) 	{ lib=(struct Library *)MathIeeeDoubBasBase;	CloseLibrary(lib); }

	if(MathIeeeDoubTransBase)	{ lib=(struct Library *)MathIeeeDoubTransBase;	CloseLibrary(lib); }

	if(UtilityBase)	            { lib=(struct Library *)UtilityBase;	        CloseLibrary(lib); }

	if(CxBase)					{ lib=(struct Library *)CxBase;			        CloseLibrary(lib); }

	if(IconBase)				{ lib=(struct Library *)IconBase;		        CloseLibrary(lib); }
}

int main(int alen, char *aptr)
{
	int return_status;
	int argc;
	char **argv;

	if(__OpenLibs())
	{
		if(__build_argc_argv(alen,aptr,&argc,&argv))
		{
			return_status=_X__main(argc,argv);

			__destroy_argc_argv();
		}
		else
			return_status=RETURN_FAIL;

		__CloseLibs();
	}
	else
		return_status=RETURN_FAIL;

	return return_status;
}

	/*
	 * MyGetProgramName()
	 *
	 * Returns a pointer to the name of the program. The User is responsible
	 * to free the pointer with FreeVec()!
	 *
	 * a maximum of 100 characters (incl. zero) are returned
     *
     * from WB there is no name, so you get a ZERO pointer!
	 */

static char *__MyGetProgramName(void)
{
	UBYTE Buffer[100];

	if(GetProgramName(Buffer, 100))
	{
		char *mem=(char *)AllocVec(100, 0);
		if(mem)
			strcpy(mem, (char *)Buffer);

		return mem;
	}
	else
		return NULL;
}


#define main _X__main

#ifdef __cplusplus
}
#endif
