/* Created 11/08/87 by -=+SDB+=- from file _main.c provided by Manx */
/* Copyright (C) 1987 by Scott Ballantyne */
/* May be freely used by ARP users/supporters */
/* Memory is allocated for the MANX device buffers, etc., but the
 * ARP tracking functions are used.
 * tweeked for v39
 * further tweeked to handle v1.4 workbench startup
 */

extern long _savsp, _stkbase;

extern int errno, Enable_Abort;

extern int _argc;
extern char **_argv;
extern struct WBStartup *WBenchMsg;

extern struct _dev *_devtab;
extern short _numdev;

extern struct ArpBase *ArpBase;
extern void *IntuitionBase, *GfxBase, *DOSBase;

extern struct ExecBase *SysBase;

/* !!! alot of things here depend on receiving WBenchMsg before opening arp.library */

#ifdef DETACH
static long _alen = 0;
#ifdef PARENT
struct Process *_parent_proc = NULL;
#endif /* PARENT */
#endif /* DETACH */

struct WBStartup *	GetMsg(struct MsgPort *);
void *			OpenLibrary(char *,LONG);

_main(alen, aptr)
long alen;
char *aptr;
{
	register struct Process *pp;

	pp = (struct Process *)SysBase -> ThisTask;

#ifdef DETACH

	/* !!! alen is here because pr_CLI is NULL for bg task, but _alen (hopefully) isn't */

	if(!pp -> pr_CLI && !_alen)
#else
	if(!pp -> pr_CLI)
#endif
	{
		WaitPort(&pp -> pr_MsgPort);
		WBenchMsg = (struct WBStartup *)GetMsg(&pp -> pr_MsgPort);
	}

	if(!(ArpBase = (struct ArpBase *)OpenLibrary (ArpName,ArpVersion)))
	{
		complain();
		Forbid();

		if(WBenchMsg)
			ReplyMsg((struct Message *)WBenchMsg);

		return(RETURN_FAIL);
	}

	if(!DOSBase)
		DOSBase = ArpBase -> DosBase;

	GfxBase		= ArpBase -> GfxBase;
	IntuitionBase	= ArpBase -> IntuiBase;

#ifdef DETACH
#ifdef STICKY
	if(Strcmp(&aptr[0],"STICKY"))
#endif /* STICKY */
	{
		void do_detach();

		if(!WBenchMsg)
			do_detach(&alen, &aptr);
	}
#ifdef STICKY
	}
#endif /* STICKY */
#endif /* DETACH */

	if(!(_devtab = ArpAlloc(_numdev * sizeof(struct _dev))))
	{
		Alert(AG_NoMemory,NULL);
		ArpExit(RETURN_FAIL,ERROR_NO_FREE_STORE);
	}

	_devtab[0] . mode = O_RDONLY;
	_devtab[1] . mode = _devtab[2] . mode = O_WRONLY;

	_stkbase = _savsp - *((long *)_savsp + 1) + 8;

	/* If compiled using the stack overflow checking function,
	 * the 'MANX' ID helps _stkchk() to determine if the stack
	 * upper bound has been overridden.
	 */

	*(long *)_stkbase = 'MANX';

	if(!WBenchMsg)
	{
#ifdef STICKY
		if(!Strcmp(&aptr[0],"STICKY"))
		{
			_devtab[0].mode |= O_STDIO;	/* shouldn't close if STICKY */
			_devtab[1].mode |= O_STDIO;

			alen -= 6;			/* remove STICKY command line argument */
			aptr += 6;
		}
#endif /* STICKY */

		_cli_parse(pp, alen, aptr);
		Enable_Abort = 1;

#ifndef DETACH
		_devtab[0] . mode |= O_STDIO;		/* shouldn't close if CLI */
		_devtab[1] . mode |= O_STDIO;
#endif /* DETACH */

	      /* !!! wb 1.4 tweek */

		_devtab[0] . fd = Input();

		if(_devtab[1] . fd = Output())
			_devtab[2] . fd = Open("*", MODE_OLDFILE);

	      /* !!! wb 1.4 tweek */
	}
	else
	{
		/* !!! wb 1.4 tweek */

		_devtab[0] . mode |= O_STDIO;		/* shouldn't close if WB opened something for us */
		_devtab[1] . mode |= O_STDIO;
		_devtab[2] . mode |= O_STDIO;

		/* !!! wb 1.4 tweek */

		if(WBenchMsg -> sm_ArgList)
			CurrentDir((BPTR)WBenchMsg -> sm_ArgList -> wa_Lock);

		_wb_parse(pp, WBenchMsg);
		_argv = (char **)WBenchMsg;

		/* !!! wb 1.4 tweek */

		_devtab[0] . fd = Input();
		_devtab[1] . fd = _devtab[2] . fd = Output();

		/* !!! wb 1.4 tweek */
	}

	exit(main(_argc, _argv));	/* Need to also close files, etc. */
}

static
complain()
{
	BPTR output;
	static char complaint1[] = "You need arp.library V39+";
	static char complaint2[] = "\n";
	static struct IntuiText comptext = { AUTOFRONTPEN, 0, JAM1, 30, 15, NULL, (void *)complaint1 };
	static struct IntuiText oktext = { AUTOFRONTPEN, AUTOBACKPEN, AUTODRAWMODE, AUTOLEFTEDGE, AUTOTOPEDGE, NULL, (void *)"Ok" };
	struct Process *pp;

	pp = (struct Process *)SysBase -> ThisTask;

	if(pp -> pr_CLI && (DOSBase = (void *)OpenLibrary ("dos.library",33L)) && (output = Output()))
	{
		Write(output, complaint1, sizeof(complaint1-1));
		Write(output, complaint2, sizeof(complaint2-1));
	}
	else
	{
		if(IntuitionBase = (void *)OpenLibrary ("intuition.library",33L))
		{
			AutoRequest (NULL,&comptext,NULL,&oktext,0L,0L,320L,72L);
			CloseLibrary ((struct Library *)IntuitionBase);
		}
		else
			Alert(AG_OpenLib | AO_ArpLib, 0L);
	}

	if(DOSBase)
	{
		CloseLibrary ((struct Library *)DOSBase);
		DOSBase = NULL;
	}
}

#ifdef DETACH
extern long _stack, _priority, _BackGroundIO;
extern char *_procname;
BPTR _Backstdout = 0;
extern BPTR _detach_curdir;
extern char *_detach_name;
static char *_aptr = 0;

static void
do_detach(long *alen,char **aptr)
{
	struct Process *pp = (struct Process *)SysBase -> ThisTask;

	if(pp -> pr_CLI)                       /* first time through!! */
	{
		register char *cp;
		register struct CommandLineInterface *cli;
#ifdef PARENT
		_parent_proc = pp;
#endif /* PARENT */

		CurrentDir(_detach_curdir = CurrentDir(NULL));

		_detach_curdir = DupLock(_detach_curdir);

		cli = (struct CommandLineInterface *)BADDR(pp -> pr_CLI);

		if(!_stack)
			_stack = cli -> cli_DefaultStack * 4;

		if(_BackGroundIO)
			_Backstdout = (BPTR)Open("*", MODE_OLDFILE);

		_alen = *alen;

		if(_aptr = DosAllocMem(_alen))
		{
			CopyMem(*aptr, _aptr, _alen);

			cp = (char *)BADDR(cli -> cli_CommandName);

			if(_detach_name = DosAllocMem(cp[0] + 1))
			{
				CopyMem(cp,_detach_name,cp[0] + 1);

				if(CreateProc(_procname,_priority,cli -> cli_Module,_stack))
				{
					cli -> cli_Module = NULL;

					ArpExit(0,0);
				}

				DosFreeMem(_detach_name);
			}

			DosFreeMem(_aptr);
		}

		ArpExit(20,ERROR_NO_FREE_STORE);
	}

		/* !!! why is this strcmp() here???
		 *
		 * Olsen says: This strcmp succeeds if the detach
		 * startup code has successfully created the background
		 * process with the name given in '_procname'.
		 *
		 * There is a nasty pitfall; say '_procname = "foo";' 
		 * the resulting program is called 'foo', too, and is
		 * called from Workbench. What happens? Bang!
		 * pp->pr_CLI is zero and the strcmp succeeds.
		 * If 'foo' hasn't crashed yet it will crash on exit.
		 *
		 * Note that the Arp _main() routine fixes this bug
		 * by taking a look on WBenchMsg before calling do_detach.
		 */

	else
	{
			/* second time */

		if(!strcmp(pp -> pr_Task . tc_Node . ln_Name, _procname))
		{
			register long *lp;
			register struct DefaultTracker *tr;

			struct DefaultTracker *GetTracker(LONG);

			if(tr = GetTracker(TRAK_SEGLIST))
			{
				lp = (long *)BADDR(pp -> pr_SegList);

				tr -> dt_Object . dt_Resource = (CPTR)lp[3];
			}

			if(tr = GetTracker(TRAK_DAMEM))
				tr -> dt_Object . dt_Resource = (CPTR)_aptr;

			if(tr = GetTracker(TRAK_DAMEM))
				tr -> dt_Object . dt_Resource = (CPTR)_detach_name;

			if(tr = GetTracker(TRAK_LOCK))
				tr -> dt_Object . dt_Resource = (CPTR)_detach_curdir;

			CurrentDir(_detach_curdir);

			pp -> pr_COS = _Backstdout;

			*alen = _alen;
			*aptr = _aptr;
		}
	}
}
#endif /* DETACH */
