/*
    (C) 1995-96 AROS - The Amiga Replacement OS
    $Id: startup.c,v 1.10 1997/01/29 19:09:47 digulla Exp $

    Desc: Common startup code
    Lang: english
*/
#include <setjmp.h>
#include <dos/dos.h>
#include <exec/memory.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <aros/asmcall.h>
#if 1
#   include <aros/debug.h>
#endif

/* Don't define symbols before the entry point. */
extern struct ExecBase * SysBase;
extern int main (int argc, char ** argv);
extern APTR __startup_mempool; /* malloc() and free() */
extern jmp_buf __startup_jmp_buf;
extern LONG __startup_error;

/*
    This won't work for normal AmigaOS because you can't expect SysBase to
    be in A6. The correct way is to use *(struct ExecBase **)4 and because
    gcc emits strings for a certain function _before_ the code the program
    will crash immediately because the first element in the code won't be
    valid assembler code.
*/
AROS_UFH3(LONG, entry,
    AROS_UFHA(char *,argstr,A0),
    AROS_UFHA(ULONG,argsize,D0),
    AROS_UFHA(struct ExecBase *,sysbase,A6)
)
{
    char * args,
	** argv,
	 * ptr;
    int    argc,
	   argmax;
    __startup_error = RETURN_FAIL;

    SysBase=sysbase;

    /* Copy args into buffer */
    if (!(args = AllocMem (argsize+1, MEMF_ANY)) )
    {
	argv = NULL;
	goto error;
    }

    ptr = args;

    while ((*ptr++ = *argstr++));

    /* Find out how many arguments we have */
    for (argmax=1,ptr=args; *ptr; )
    {
	if (*ptr == ' ' || *ptr == '\t')
	{
	    /* Skip whitespace */
	    while (*ptr && (*ptr == ' ' || *ptr == '\t'))
		ptr ++;
	}

	if (*ptr == '"')
	{
	    /* "..." argument ? */
	    argmax ++;

	    ptr ++;

	    /* Skip until next " */
	    while (*ptr && *ptr != '"')
		ptr ++;

	    if (*ptr)
		ptr ++;
	}
	else if (*ptr)
	{
	    argmax ++;

	    while (*ptr && *ptr != ' ' && *ptr != '\t')
		ptr ++;
	}
    }

    if (!(argv = AllocMem (sizeof (char *) * argmax, MEMF_ANY)) )
    {
	goto error;
    }

    /* Find out how many arguments we have */
    for (argc=1,ptr=args; *ptr; )
    {
	if (*ptr == ' ' || *ptr == '\t')
	{
	    /* Skip whitespace */
	    while (*ptr && (*ptr == ' ' || *ptr == '\t'))
		ptr ++;
	}

	if (*ptr == '"')
	{
	    /* "..." argument ? */
	    ptr ++;
	    argv[argc++] = ptr;

	    /* Skip until next " */
	    while (*ptr && *ptr != '"')
		ptr ++;

	    /* Terminate argument */
	    if (*ptr)
		*ptr ++ = 0;
	}
	else if (*ptr)
	{
	    argv[argc++] = ptr;

	    while (*ptr && *ptr != ' ' && *ptr != '\t')
		ptr ++;

	    /* Not at end of string ? Terminate arg */
	    if (*ptr)
		*ptr ++ = 0;
	}
    }

    DOSBase = (struct DosLibrary *)OpenLibrary (DOSNAME, 39);

    /* Get name of program * /
    argv[0] = GetProgrammName (); */
    argv[0] = "dummy";

#if 0
kprintf ("arg(%d)=\"%s\", argmax=%d, argc=%d\n", argsize, argstr, argmax, argc);
{
int t;
for (t=0; t<argc; t++)
    kprintf ("argv[%d] = \"%s\"\n", t, argv[t]);
}
#endif

    if (DOSBase != NULL)
    {
	if (!setjmp (__startup_jmp_buf))
	    __startup_error = main (argc, argv);

	CloseLibrary((struct Library *)DOSBase);
    }

error:
    if (args)
    {
	if (argv)
	    FreeMem (argv, sizeof (char *) * argmax);

	FreeMem (args, argsize+1);
    }

    if (__startup_mempool)
	DeletePool (__startup_mempool);

    return __startup_error;
} /* entry */

struct ExecBase *SysBase;
struct DosLibrary *DOSBase;

APTR __startup_mempool = NULL;
jmp_buf __startup_jmp_buf;
LONG __startup_error;

/*	Stub function for GCC __main().

	The __main() function is originally used for C++ style constructors
	and destructors in C. This replacement does nothing and gets rid of
	linker-errors about references to __main().
*/

void __main(void)
{
/* Do nothing. */
}

