/* x_main.c - self spawning startup code:
 *   from CLI - spawns a new process and returns to CLI
 *   from spawned process - runs normally except no stdio files opened
 *   from Workbench - runs normally
 */

/*    (notes from _main.c)
 *	This is common startup code for both the CLI and the WorkBench.
 *	When called from the WorkBench, argc is 0 and argv points to a
 *	WBStartup type of structure.
 */
/* _main.c is Copyright (C) 1986,1987 by Manx Software Systems, Inc. */


#include <fcntl.h>
#include <exec/alerts.h>
#include <exec/memory.h>
#include <libraries/dosextens.h>
#include <workbench/startup.h>
#include <functions.h>


/* some statics are given values (even if 0) to prevent them from being
   placed into udata and zeroed by crt0 */

extern long _savsp, _stkbase;

extern int errno;

extern int _argc, _arg_len;
extern char **_argv, *_arg_lin;
extern struct WBStartup *WBenchMsg;

extern struct _dev *_devtab;
extern short _numdev;

static long seg=0;
static char clistart;

_main(alen, aptr)
long alen;
char *aptr;
{
	register struct Process *pp, *_FindTask();
	void *_OpenLibrary(), *_GetMsg(), *_AllocMem();
	long _Input(), _Output(), _Open();
	static int t_argc=0, t_arg_len=0;
	static char **t_argv=0, *t_arg_lin=0;
	static BPTR t_cdir=0;

	if ((_devtab = _AllocMem(_numdev*(long)sizeof(struct _dev),
													MEMF_CLEAR)) == 0) {
		Alert(AG_NoMemory, 0L);
#asm
		move.l	__savsp,sp		;get back original stack pointer
		rts						;and exit
#endasm
	}

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

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

	pp = _FindTask(0L);
	if (pp->pr_CLI) {
		struct CommandLineInterface *cli = (struct CommandLineInterface *) ((long)pp->pr_CLI << 2);
		long *bcpl;
		void *tmpdosbase;

		seg = cli->cli_Module;

		if ((tmpdosbase = OpenLibrary("dos.library", 33L)) == 0) {      /* v1.1 compatibility */
		    bcpl = (long *)*((long *)*((long *)*((long *)*((long *) _savsp+2)+1)-3)-3)+107;
		    if (seg != *bcpl) _exit (1);
		}
		else {
		    CloseLibrary(tmpdosbase);
		    bcpl = 0;
		}

	    /*	  bcpl = (long *)*((long *)*((long *)*((long *)*((long *)pp->pr_ReturnAddr+1)+1)-3)-3)+106;   old stuff */

		_cli_parse(pp, alen, aptr);
		_devtab[0].mode |= O_STDIO;		/* shouldn't close if CLI */
		_devtab[1].mode |= O_STDIO;

		t_arg_lin = _arg_lin;
		t_arg_len = _arg_len;
		t_argv = _argv;
		t_argc = _argc;
		if (pp->pr_CurrentDir) t_cdir = DupLock (pp->pr_CurrentDir);
		clistart = 1;

		_Forbid();		/* prevent starting new task until this one goes away (uses common data) */
		if (CreateProc (_argv[0], 0L, seg, cli->cli_DefaultStack * 4)) {
		    _arg_lin = 0;	    /* prevent freeing these */
		    if (bcpl) *bcpl = 0;
		    cli->cli_Module = 0;
		}

		_exit(0);
	}

	if (t_argc) {
		_arg_lin = t_arg_lin;
		_arg_len = t_arg_len;
		_argc = t_argc;
		_argv = t_argv;
		_CurrentDir (t_cdir);
	}
	else {
		_WaitPort(&pp->pr_MsgPort);
		WBenchMsg = _GetMsg(&pp->pr_MsgPort);
		if (WBenchMsg->sm_ArgList)
			_CurrentDir(WBenchMsg->sm_ArgList->wa_Lock);
		_wb_parse(pp, WBenchMsg);
		_argv = (char **)WBenchMsg;
	}
	_devtab[0].fd = _Input();
	if (_devtab[1].fd = _Output())
		_devtab[2].fd = _Open("*", MODE_OLDFILE);
	main(_argc, _argv);
	exit(0);
}


extern void *MathBase, *MathTransBase, *MathIeeeDoubBasBase;
void (*_cln)();

_exit(code)
{
	long ret = code;
	register int fd;

	if (_devtab) {
		for (fd = 0 ; fd < _numdev ; fd++)
			close(fd);
		_FreeMem(_devtab, _numdev*(long)sizeof(struct _dev));
	}
	if (_cln)
		(*_cln)();
	if (MathTransBase)
		_CloseLibrary(MathTransBase);
	if (MathBase)
		_CloseLibrary(MathBase);
	if (MathIeeeDoubBasBase)
		_CloseLibrary(MathIeeeDoubBasBase);
	{
#asm
	mc68881
	move.l	4,a6				;get ExecBase
	btst.b	#4,$129(a6)			;check for 68881 flag in AttnFlags
	beq		1$					;skip if not
	move.l	a5,-(sp)
	lea		2$,a5
	jsr		-30(a6) 			;do it in supervisor mode
	move.l	(sp)+,a5
	bra		1$
2$
	clr.l	-(sp)
	frestore (sp)+				;reset the ffp stuff
	rte							;and return
1$
#endasm
	}
	if (WBenchMsg == 0) {
		if (_arg_lin) {
			_FreeMem(_arg_lin, (long)_arg_len);
			_FreeMem(_argv, (long)(_argc+1)*sizeof(*_argv));
		}
		if (!clistart) {
		    BPTR oldcdir = CurrentDir(NULL);

		    if (oldcdir) UnLock(oldcdir);

		    _Forbid();

		    if (seg) UnLoadSeg (seg);
		}
	}
	else {
		_Forbid();
		_ReplyMsg(WBenchMsg);
	}
	{
#asm
		move.l	-4(a5),d0		;pick up return exit code
		move.l	__savsp#,sp		;get back original stack pointer
		rts						;and exit
#endasm
	}
}

