*
* C initial startup procedure under AmigaDOS
* 

        INCLUDE "exec/types.i"
        INCLUDE "exec/alerts.i"
        INCLUDE "exec/nodes.i"
        INCLUDE "exec/lists.i"
        INCLUDE "exec/ports.i"
        INCLUDE "exec/libraries.i"
        INCLUDE "exec/tasks.i"
        INCLUDE "exec/memory.i"
        INCLUDE "exec/execbase.i"
        INCLUDE "libraries/dos.i"
        INCLUDE "libraries/dosextens.i"
        INCLUDE "exec/funcdef.i"
        INCLUDE "exec/exec_lib.i"
        INCLUDE "libraries/dos_lib.i"
        INCLUDE "workbench/startup.i"

AbsExecBase EQU 4

TINY    EQU     0
callsys macro
        CALLLIB _LVO\1
        endm
        
	xdef	XCEXIT			; exit(code) is standard way to leave C.
	xdef 	@XCEXIT
	
	xref	LinkerDB		; linker defined base value
	xref	_BSSBAS		; linker defined base of BSS
	xref	_BSSLEN		; linker defined length of BSS

	xref	_main			; Name of C program to start with.
        xref    __fpinit                * initialize floating point
        xref    __fpterm                * terminate floating point

*	library references

	csect	_NOMERGE,0,0,0,4
	xref	MemCleanup
	xref	FindTask

start:
        movem.l d1-d6/a0-a6,-(a7)
REGSIZE EQU     (6+7)*4
        lea     REGSIZE(a7),A5         * determine old stack pointer
        move.l  a0,a2                  * save command pointer
        move.l  d0,d2                  * and command length
        lea     LinkerDB,a4            * load base register

        move.l  AbsExecBase.W,a6
        move.l  a6,SysBase(A4)
        move.l  a7,_StackPtr(A4)       * Save stack ptr
        clr.l   WBenchMsg(A4)

*------	Clear out our BSS section
        lea     _BSSBAS,a3             * get base of BSS
        moveq   #0,d1
        move.l  #_BSSLEN,d0            * get length of BSS in longwords
        bra.s   clr_lp                 * and clear for length given
clr_bss move.l  d1,(a3)+
clr_lp  dbf     d0,clr_bss

*------ get the address of our task
	move.l	ThisTask(a6),A3

*-----  clear any pending signals
	moveq	#0,d0
	move.l	#$00003000,d1
	callsys	SetSignal

*------ are we running as a son of Workbench?
	move.l	pr_CurrentDir(A3),curdir(A4)
	tst.l	pr_CLI(A3)
	beq	fromWorkbench

*=======================================================================
*====== CLI Startup Code ===============================================
*=======================================================================

fromCLI:
*------	attempt to open DOS library:
	bsr.w	openDOS

*------ Duplicate the current directory for the called process
	move.l	curdir(A4),D1
	move.l	DOSBase(A4),A6
        callsys DupLock
        move.l  D0,curdir(A4)

*------ find command name:
	move.l	pr_CLI(A3),a0
	add.l   a0,a0			; bcpl pointer conversion
	add.l   a0,a0
	move.l	cli_CommandName(a0),a1
	add.l   a1,a1			; bcpl pointer conversion
	add.l   a1,a1

*------	collect parameters:
	move.l	d2,d0		; get command line length
	moveq.l	#0,d1
	move.b	(a1)+,d1
        move.l  A1,D4                   ;save our pointer
	move.l	d1,d3
	add.l	d1,d1			; double length since we copy it twice
	add.l	d1,d0			; add length of command name
	addq.l	#5,d0			; allow for space after command	
	addq.l	#4,d0			; As well as for the roundup
*                          ; changed from 5 to 9 for quotes
*                                         
*------	We have the length of the command string to be copied.
*------	Allocate space for it.
*------	Round up to the nearest 4 bytes
	lsl.l	#2,d0
	add.l	memsize(A4),d0
	move.l	d0,memsize(A4)

************************************************************************
************************************************************************
******** Allocate and copy over the code to do the magic stuff *********
************************************************************************
************************************************************************

	lea	memlist(A4),A0
        move.l  AbsExecBase.W,a6
	callsys	AllocEntry		;get a place to put the code
*	btst.l	#31,d0			;did we get the memory we asked for?
*	beq	cliexit			;no, can't do anything then
	move.l	D0,A1
	move.l	D0,-(A7)		;remember the chunk we allocated

*------ Now we copy the code over
	movea.l	ML_SIZE+ME_ADDR(A1),A1	;locate our allocated block

*------	Copy over the command line to the allocated area
	lea	commandbuf-copybeg(A1),A3

*------	At this point, we have:
*		A0 - Work pointer
*		A1 - Pointer to Allocated memory block
*		A2 - Pointer to program name
*		A3 - Pointer to target buffer
*		A3 - Pointer to our process structure
*		D0 - Work register
*		D1 - Work register
*		D2 - length of command name
*		D3 - length of program name
*               D4 - Pointer to program name

	movea.l	D4,A0			; Load program name
	move.l	D3,D0			;      and length
        move.b  #'"',(a3)+
	bra.s	cpy1
cpycmd:	move.b	(A0)+,(A3)+		; copy over the command name
cpy1:	dbf	d0,cpycmd
        move.b  #'"',(a3)+
	move.b	#' ',(A3)+		; add the space delimiter

	move.l	A2,A0			; Load command text
	move.l	D2,D0			;      and length
	bra.s	cpy2
cpylin:	move.b	(A0)+,(A3)+
cpy2:	dbf	d0,cpylin
	clr.b	(A3)+

*------	Now copy over the program name
	move.l	A3,_ProgramName(A4)
	move.l	D4,A0
	move.l	D3,D0
	bra.s	cpy3
cpypgm:	move.b	(A0)+,(A3)+
cpy3:	dbf	D0,cpypgm
	clr.b	(A3)			;don't forget trailing null on name

*------ First we want to put it into our seglist
	lea	segexit-copybeg(A1),A2
	move.l	A2,XCEXIT+2(A4)		;patch the jump instruction
	lea	start-4(PC),A2

*	Now we have:	A1 to our new fake segment
*			A2 to the start of the real seglist
	move.l	#(copyend-copybeg)/4,(A1)+
	move.l	A1,D3
	lsr.l	#2,D3			;convert it to a bptr to the list
	move.l	(A2),(A1)+		;save our next segment pointer
	clr.l	(A2)			;and kill it from the chain
*------ We have the seglist

	lea	AutoLoader(PC),A2
	move.l	#(copyend-AutoLoader)-1,D0
copyit	move.b	(A2)+,(A1)+
	dbf	d0,copyit

*------	See if they want to do some I/O
	tst.l	_BackGroundIO(A4)
	beq	noio
        lea     current_window(A4),A0
        move.l  A0,D1
	move.l	#1005,D2
	move.l	DOSBase(A4),A6
	callsys	Open
	move.l	d0,_Backstdout(A4)
noio:
	move.l	AbsExecBase.w,A6
	callsys	Forbid

*------ Attach the task to do the dirty work
	move.l	_procname(A4),D1	; Name of task to start
	move.l	_priority(A4),D2	; Priority of background task
	move.l	_stack(A4),D4		; Stack size of created task

	move.l	DOSBase(A4),A6
	callsys	CreateProc
	move.l	A6,A3		; restore dosbase to close it
	tst.l	D0
	bne	ok

*------ Serious problems.  For some reason the CreateProc failed.
*------ We need to free the AlocEntry memory and go home
	move.l	(A7)+,A2
	movea.l	ML_SIZE+ME_ADDR(A2),A1	;locate our allocated block
*------ Also must get rid of current directory
        move.l  curdir(A4),D1
        callsys UnLock

        move.l  A2,A0
	move.l	AbsExecBase.w,A6
	callsys	FreeEntry
	move.l	#104,D0
	bra	cliexit

ok:
*------ The task started ok, attach the memory we allocated to
*------	its task control block
	move.l	D0,A2

	move.l	(a7)+,A1		;locate the memory we allocated
	lea	-pr_MsgPort(A2),A2
	lea	TC_MEMENTRY(A2),A0


*	ADDTAIL
	LEA	LH_TAIL(A0),A0
	MOVE.L	LN_PRED(A0),D0
	MOVE.L	A1,LN_PRED(A0)
	MOVE.L	A0,(A1)
	MOVE.L	D0,LN_PRED(A1)
	MOVE.L	D0,A0
	MOVE.L	A1,(A0)

	move.l	#0,D0

cliexit:
	move.l	AbsExecBase.w,A6
	callsys	Permit
	move.l	A3,A1
	move.l	AbsExecBase.w,A6
	callsys	CloseLibrary
	movem.l	(a7)+,d1-d6/a0-a6
	rts

*=======================================================================
*====== Workbench Startup Code =========================================
*=======================================================================

fromWorkbench:

	move.l	TC_SPLOWER(A3),_base(A4)	; set base of stack
        add.l   #128,_base(A4)          ;allow for parms overflow
*------ open the DOS library:
	bsr.w	openDOS

	lea	xcexit(PC),A2
	move.l	A2,XCEXIT+2(A4)		;patch the jump instruction
	
*------ we are now set up.  wait for a message from our starter
	bsr.w	waitmsg
	move.l	d0,WBenchMsg(A4)
	move.l	d0,-(SP)
*
	move.l	d0,a2			; get first argument
	move.l	sm_ArgList(a2),d0
	beq.s	do_cons
	move.l	DOSBase(A4),a6
	move.l	d0,a0
	move.l	wa_Lock(a0),d1
	move.l	d1,curdir(A4)
	callsys	CurrentDir
do_cons:
	move.l	sm_ToolWindow(a2),d1	; get the window argument
	beq.s	do_main
	move.l	#MODE_OLDFILE,d2
	callsys	Open
	move.l	d0,stdin(A4)
	beq.s	do_main
	lsl.l	#2,d0
	move.l	d0,a0
	move.l	fh_Type(a0),pr_ConsoleTask(A3)
do_main:
	move.l	WBenchMsg(A4),a0		; get address of workbench message
	move.l	a0,-(a7)		; push argv
	pea	NULL(A4)		; push argc
	move.l	sm_ArgList(a0),a0	; get address of arguments
	move.l	wa_Name(a0),_ProgramName(A4)	; get name of program
*------ For startup from workbench, there is no reason to go through
*------ The fancy stuff to make the startup work.  Just run the
*------ Code directly
	jsr	__fpinit(PC)
	jsr	_main
	moveq.l	#0,d0
	bra.w	exit2
	

************************************************************************
************************************************************************
*************                                              *************
************* Start of code that is copied to fake segment *************
*************                                              *************
************************************************************************
************************************************************************

copybeg:
	DC.L	(copyend-copybeg)/4
next:	DC.L	0
AutoLoader:
	move.l	a7,d0
	movem.l	d1-d6/a0-a6,-(a7)
	move.l	d0,a5
	move.l	AbsExecBase.w,a6
	lea	LinkerDB,A4		; load base register
	move.l	a7,_StackPtr(A4)

	bsr.w	openDOS
	suba.l	a1,a1

	suba.l	a1,a1
	callsys	FindTask
	move.l	d0,A3

	move.l	TC_SPLOWER(A3),_base(A4)	; set base of stack
        add.l   #128,_base(A4)          ;allow for parms overflow

	move.l	pr_SegList(A3),a0	;locate the segment list
	add.l	A0,A0
	add.l	A0,A0			;and convert to an APTR
	move.l	12(A0),A1		;so we can access the segments
	add.l	A1,A1
	add.l	A1,A1

	move.l	(A1),seglist(A4)	;save the remainder for later
	move.l	(A1),12(A0)		;cut off our segment

        move.l  curdir(A4),D1
	move.l	DOSBase(A4),a6
        callsys CurrentDir

	pea	commandbuf(PC)
        jsr     __fpinit
	jsr	_main		        ; call C entrypoint
	addq	#4,A7


*------ Unlock the directory we set up for them
segexit:
	move.l	DOSBase(A4),a6
        move.l  curdir(A4),D1
        callsys UnLock

	moveq.l	#0,d0			; set successful status
xcexit:
exit2:
	IFEQ	TINY
	move.l	_ONEXIT(A4),d0		; exit trap function?
	beq.s	exit3
	move.l	d0,a0
	jsr	(a0)
	ENDC

exit3	jsr	MemCleanup		; cleanup leftover memory alloc.

	jsr	__fpterm

done_1c:
*------ if we ran from CLI, skip workbench cleanup:
	tst.l	WBenchMsg(A4)
	beq.s	exitToDOS
	move.l	stdin(A4),d1
	beq.s	done_4
	move.l	DOSBase(A4),a6
	callsys	Close
done_4:

*------ return the startup message to our parent
*	we forbid so workbench can't UnLoadSeg() us
*	before we are done:
	move.l	AbsExecBase.w,A6
	callsys	Forbid
	move.l	WBenchMsg(A4),a1
	callsys	ReplyMsg

*------ this rts sends us back to DOS:
exitToDOS:
        movea.l _StackPtr(a4),a3        ; Put old stack pointer somewhere safe.

*------	They are done so unload them
	move.l	seglist(A4),D1
	move.l	DOSBase(A4),a6
	callsys	UnLoadSeg

        move.l  a6,a1
	move.l	AbsExecBase.w,a6
	callsys	CloseLibrary		; close Dos library


	movea.l  a3,SP			; restore stack ptr
	movem.l	(a7)+,d1-d6/a0-a6
	rts

*-----------------------------------------------------------------------
*  Open the DOS library:

openDOS
		lea	DOSName(A4),A1
		moveq.l	#0,D0
		callsys	OpenLibrary
		move.l	D0,DOSBase(A4)
		beq	noDOS
		rts
*-----------------------------------------------------------------------
noDOS:
		moveq.l	#100,d0
		bra	exit2

copyend:
commandbuf:

************************************************************************
************************************************************************
**************                                            **************
************** End of code that is copied to fake segment **************
**************                                            **************
************************************************************************
************************************************************************

*-----------------------------------------------------------------------
* This routine gets the message that workbench will send to us
* called with task id in A3

waitmsg:
		lea	pr_MsgPort(A3),a0  	; our process base
		callsys	WaitPort
		lea	pr_MsgPort(A3),a0  	; our process base
		callsys	GetMsg
		rts

	csect	__MERGED,1,0,0,4

*------	These externals control the task that is started
	xref	_BackGroundIO		; flag to indicate background task
*					; wants to do I/O
	xref	_stack			; stack space for created task
	xref	_procname		; name of process to be created
	xref	_priority		; priority to create process at

	xref	DOSBase
	xref	MathBase
	xref	MathTransBase
*
	xdef	NULL,SysBase,WBenchMsg
	xdef	curdir,_mbase,_mnext,_msize,_tsize
	xdef	_oserr,_OSERR,_FPERR,_SIGFPE,_ONERR,_ONEXIT,_ONBREAK
	xdef	_SIGINT,_Backstdout
	xdef	_ProgramName,_StackPtr,_base
*
*		cnop	0,4
memlist	ds.b	LN_SIZE
		dc.w	1
		dc.l	MEMF_PUBLIC
memsize	dc.l	copyend-copybeg

XCEXIT	
@XCEXIT		dc.w	$4ef9
		dc.l	0
seglist		dc.l	0
NULL		dc.l	0		;
_base		dc.l	0		; base of stack
_mbase		dc.l	0		; base of memory pool
_mnext		dc.l	0		; next available memory location
_msize		dc.l	0		; size of memory pool
_tsize		dc.l	0		; total size?
_oserr		equ	*
_OSERR		dc.l	0
_FPERR		dc.l	0
_SIGFPE		dc.l	0
_SIGINT		dc.l	0
_ONERR		dc.l	0
_ONEXIT		dc.l	0
_ONBREAK	dc.l	0
curdir		dc.l	0
SysBase		dc.l	0
WBenchMsg	dc.l	0
_StackPtr	dc.l	0
dosCmdLen	dc.l	0
dosCmdBuf	dc.l	0
stdin		dc.l	0
_Backstdout	dc.l	0		;filehandle for I/O
_ProgramName	dc.l	0
DOSName 	dc.b	'dos.library',0
current_window	dc.b	'*',0
		END
