;*************************************************************************
;*                                                                       *
;* This is my private C startup routine. If you use this routine,        *
;* remember to credit me. Below is a desciption of all the defines you   *
;* can use when you assemble it. When you compile, link with the link    *
;* file (Startup.o) as a custom startup.                                 *
;*                                                                       *
;* When you use this routine, you don't need to open the dos & intuition *
;* library. This is done for you.                                        *
;*                                                                       *
;* Assemble with the following command: asm [defines] Startup.a          *
;*                                                                       *
;* where [defines] can be one of more of the following arguments:        *
;*                                                                       *
;* -dUTILLIB      = If you use the utility library for math, define this.*
;*                                                                       *
;* -dBACK         = Run the main function as a background process.       *
;*                  You need to define this variable:                    *
;*                  char ProgramName[] = "You program";                  *
;*                                                                       *
;*                  Note that you must NOT use smallcode when you link.  *
;*                                                                       *
;* -dWBARGS       = WorkBench arguments (tooltypes). You have to make    *
;*                  the following initialized variables:                 *
;*                  ULONG ArgList[] = {0,0,0,....,0};                    *
;*                                                                       *
;*                  You also need this function to parse the tooltypes:  *
;*                  void __asm TestToolTypes                             *
;*                             (__register a0 struct DiskObject* dobj);  *
;*                  You don't need to open the icon.library, this is     *
;*                  already done by the startup routine.                 *
;*                                                                       *
;* -dCLIARGS      = CLI arguments. You have to make the following        *
;*                  initialized variables:                               *
;*                  char CLIString[] = "SWITCH/S";                       *
;*                  ULONG ArgList[] = {0,0,0,....,0};                    *
;*                                                                       *
;* -dNOPAR        = If you use CLI arguments and you want to startup     *
;*                  when the user haven't give you any arguments.        *
;*                                                                       *
;* -dPRIGET=xx    = This is the number of the argument in your CLI       *
;*                  ArgList, which defines the priority.                 *
;*                                                                       *
;* -dNOCLIBACK=xx = Set this to the number of arguments you have. This   *
;*                  is used to test if the user has gived you any        *
;*                  arguments so the startup routine won't startup as a  *
;*                  background process. Do only use this together with   *
;*                  the BACK define.                                     *
;*                                                                       *
;* -dPRI=xx       = Set this to your task priority. Default is 0.        *
;*                                                                       *
;* -dKICKVER=xx   = Which kickstart version you require. Has to be       *
;*                  minimum 37 which is the default.                     *
;*                                                                       *
;* If you want to change the stack size, do as following:                *
;*                                                                       *
;* long __stack = xxxxx;                                                 *
;*                                                                       *
;*************************************************************************
;-------------------------------------------------------------------------
; Include all the stuff we need
;

	include	"exec/types.i"
	include "exec/libraries.i"
	include	"exec/memory.i"
	include "exec/funcdef.i"
	include	"workbench/startup.i"

	include	"dos/dosextens.i"
	include	"dos/dostags.i"

	include	"lvo/exec_lib.i"
	include	"lvo/dos_lib.i"
	include	"lvo/intuition_lib.i"
	include	"lvo/icon_lib.i"
;-------------------------------------------------------------------------
; Make the XDEF and XREF
;

	IFD	BACK
	SECTION	Startup,code
	ELSE
	SECTION	Text,code
	ENDC

	XDEF	__startup

	XREF	_LinkerDB		;Linker Defined Base Value
	XREF	__BSSBAS		;Linker Defined Base Of BSS
	XREF	__BSSLEN		;Linker Defined Length Of BSS
	XREF	___stack

	XREF	@main			;Start Address Of Main Program

	XREF	_CLIString		;CLI Argument String
	XREF	_ArgList		;Argument List Array
	XREF	_ProgramName		;Name Of The Program

	XREF	@TestToolTypes		;ToolType Test Routine
;-------------------------------------------------------------------------
; Some usefull macros
;

CALLSYS	macro
	CALLLIB	_LVO\1
	endm
;-------------------------------------------------------------------------
	IFD	BACK
BACK1	EQU	0
	ELSE
BACK1	EQU	1
	ENDC

	IFD	NOCLIBACK
NOCLI	EQU	1
	ELSE
NOCLI	EQU	0
	ENDC

__startup
	bra.s	.run
;-------------------------------------------------------------------------
	dc.b	"Startup code written by Thomas Neumann in 1996",0
	cnop	0,2
;-------------------------------------------------------------------------
; The startup routine itself
;

.run	lea	_LinkerDB,a4		;Base Register
	lea	__BSSBAS,a0
	moveq	#0,d0
	move.l	#__BSSLEN,d1
	beq.s	.noclr
.clrbss	move.l	d0,(a0)+		;Clear BSS Area
	subq.l	#1,d1
	bne.s	.clrbss

.noclr	move.l	4.w,a6
	move.l	a6,_SysBase(a4)

	sub.l	a1,a1
	CALLSYS	FindTask		;Find Our Process
	move.l	d0,a5

	lea	.intnam(pc),a1
	moveq	#0,d0
	CALLSYS	OpenLibrary		;Open Intuition Library
	move.l	d0,_IntuitionBase(a4)
	beq	.errout

	IFD	KICKVER
	cmp.w	#KICKVER,LIB_VERSION(a6) ;Test For Kickstart Version
	ELSE
	cmp.w	#37,LIB_VERSION(a6)
	ENDC
	blt	.kicker

	lea	.dosnam(pc),a1
	moveq	#0,d0
	CALLSYS	OpenLibrary		;Open Dos Library
	IF	BACK1!NOCLI
	move.l	d0,_DOSBase(a4)
	ELSE
	tst.l	d0
	ENDC
	beq	.errou1
	move.l	d0,d6

	IFD	UTILLIB
	lea	.utinam(pc),a1
	moveq	#0,d0
	CALLSYS	OpenLibrary		;Open Utility Library
	move.l	d0,_UtilityBase(a4)
	bne.s	.utilok
	move.l	d6,a1
	CALLSYS	CloseLibrary		;Close Dos Library
	bra	.errou1

.utilok
	ENDC

	IFD	CLIARGS
	sub.l	a2,a2			;Clear CLI Arguments Pointer
	ENDC

	sub.l	a3,a3			;Clear WorkBench Message Pointer
	tst.l	pr_CLI(a5)		;Started From WorkBench?
	bne.s	.itcli			;Nup!

;*************************************************************************
;* WorkBench Startup                                                     *
;*************************************************************************

	move.l	pr_StackSize(a5),-(sp)
	bsr	.gework			;Get Message

	move.l	sm_ArgList(a3),d0
	beq.s	.wbout1

	move.l	d6,a6			;DOSBase
	move.l	d0,a0
	move.l	wa_Lock(a0),d1
	CALLSYS	CurrentDir		;Set Current Directory

	IFD	WBARGS
	move.l	_SysBase(a4),a6
	lea	.icnnam(pc),a1
	moveq	#0,d0
	CALLSYS	OpenLibrary		;Open Icon.library
	move.l	d0,_IconBase(a4)
	beq.s	.wbout1

	move.l	d0,a6
	move.l	sm_ArgList(a3),a0
	move.l	wa_Name(a0),a0
	CALLSYS	GetDiskObject		;Read Icon File
	tst.l	d0
	beq.s	.wbout

; Parse The ToolTypes

	move.l	d0,a0
	movem.l	d0-d7/a0-a6,-(sp)
	bsr	@TestToolTypes
	movem.l	(sp)+,d0-d7/a0-a6

; Clean Up Again

	CALLSYS	FreeDiskObject		;Free Icon Memory Again

.wbout	move.l	a6,a1
	move.l	_SysBase(a4),a6
	CALLSYS	CloseLibrary		;Close Icon.library
	ENDC

.wbout1	bra.s	.wecont

;*************************************************************************
;* CLI Startup                                                           *
;*************************************************************************

.itcli
	IFD	CLIARGS
	IFD	NOCLIBACK
	moveq	#0,d5
	ENDC

	move.l	d6,a6			;DOSBase
	move.l	#_CLIString,d1
	move.l	#_ArgList,d2
	moveq	#0,d3
	CALLSYS	ReadArgs		;Read & Parse Arguments
	tst.l	d0
	bne.s	.argok
	CALLSYS	IoErr			;Get Error Code

	IFD	NOPAR
	cmp.w	#ERROR_REQUIRED_ARG_MISSING,d0
	beq.s	.getstk
	ENDC

	move.l	d0,d1
	moveq	#0,d2
	CALLSYS	PrintFault		;Print Error Text
	bra	.geout1

.argok	move.l	d0,a2

	IFD	NOCLIBACK
	lea	_ArgList(a4),a0
	moveq	#NOCLIBACK-1,d0
.loop	tst.l	(a0)+
	bne.s	.gotarg
	dbra	d0,.loop
	bra.s	.getstk

.gotarg	moveq	#1,d5
	ENDC
	ENDC

.getstk	move.l	pr_CLI(a5),d0
	lsl.l	#2,d0
	move.l	d0,a0
	move.l	cli_DefaultStack(a0),-(sp)

;*************************************************************************
;* Start Main Program                                                    *
;*************************************************************************

.wecont
	IFD	BACK
	IFD	CLIARGS
	move.l	a2,CliArg(a4)
	ENDC

	IFD	NOCLIBACK
	tst.l	d5
	bne.s	.normst
	ENDC

	move.l	d6,a6			;DOSBase
	lea	__startup-4(pc),a0
	clr.l	(a0)

	lea	.protag(pc),a1
	move.l	#.Main,4(a1)		;Store Start Address To Run

	move.l	(sp)+,d0		;Get Stack Size
	cmp.l	___stack(a4),d0
	bge.s	.stkok
	move.l	___stack(a4),d0
.stkok	move.l	d0,12(a1)		;Store Stack Size

	IFD	PRIGET
	move.l	_ArgList+(PRIGET-1)*4(a4),d1
	beq.s	.nopri
	move.l	d1,a0
	move.l	(a0),20(a1)		;Store Priority
	ENDC

.nopri	move.l	a1,d1
	CALLSYS	CreateNewProc		;Start New Process

	move.l	_SysBase(a4),a6
	move.l	d6,a1			;DOSBase
	CALLSYS	CloseLibrary		;Close Dos.library

	IFD	NOCLIBACK
	bra	.geout1
	ENDC
	ENDC

; No Background Process Startup

	IF	BACK1!NOCLI
.normst	move.l	_SysBase(a4),a6
	move.l	(sp)+,d0		;Get Stack Size
	cmp.l	___stack(a4),d0
	bge.s	.main

; The Stack Isn't Big Enough, so We Allocate A New One.

	move.l	___stack(a4),d0
	move.l	#MEMF_CLEAR!MEMF_PUBLIC,d1
	CALLSYS	AllocMem
	move.l	d0,NewStk(a4)
	beq.s	.stkfail

	move.l	d0,StkLower(a4)
	add.l	___stack(a4),d0
	move.l	d0,StkPointer(a4)
	move.l	d0,StkUpper(a4)
	lea	StkLower(a4),a0
	CALLSYS	StackSwap		;Swap The Stacks

; Setup New Priority And Start The Main Function

.main
	IFD	PRI
	move.l	a5,a1
	moveq	#PRI,d0
	CALLSYS	SetTaskPri
	ENDC

	movem.l	d2-d7/a2-a6,-(sp)
	bsr	@main
	movem.l	(sp)+,d2-d7/a2-a6

; Remove Stack Again

	tst.l	NewStk(a4)
	beq.s	.norem
	move.l	_SysBase(a4),a6
	lea	StkLower(a4),a0
	CALLSYS	StackSwap		;Swap Back To Old Stack

	move.l	NewStk(a4),a1
	move.l	___stack(a4),d0
	CALLSYS	FreeMem			;Free Stack

.norem
.stkfail
	IFD	CLIARGS
	move.l	d6,a6			;DOSBase
	move.l	a2,d1
	CALLSYS	FreeArgs		;Free CLI Arguments
	ENDC

	move.l	_SysBase(a4),a6

	IFD	UTILLIB
	move.l	_UtilityBase(a4),a1
	CALLSYS	CloseLibrary		;Close Utility.library
	ENDC

	move.l	_IntuitionBase(a4),a1
	CALLSYS	CloseLibrary		;Close Intuition.library

	move.l	d6,a1			;DOSBase
	CALLSYS	CloseLibrary		;Close Dos.library
	ENDC

.geout1	move.l	a3,d0
	beq.s	.getout
	CALLSYS	Forbid
	move.l	a3,a1
	CALLSYS	ReplyMsg		;Reply WorkBench Message

.getout	moveq	#0,d0
	rts
;-------------------------------------------------------------------------
; Get WorkBench Message
;

.gework	lea	pr_MsgPort(a5),a0
	CALLSYS	WaitPort		;Wait For Message
	lea	pr_MsgPort(a5),a0
	CALLSYS	GetMsg			;And Get It
	move.l	d0,a3
	rts
;-------------------------------------------------------------------------
; Show Kickstart Error Message
;

.kicker	move.l	_IntuitionBase(a4),a6
	sub.l	a0,a0
	lea	.bodstr(pc),a1
	sub.l	a2,a2
	lea	.negstr(pc),a3
	moveq	#0,d0
	moveq	#0,d1
	move.w	#320,d2
	moveq	#60,d3
	CALLSYS	AutoRequest		;Show Error Requester
;-------------------------------------------------------------------------
; Error Out
;

.errou1	move.l	_SysBase(a4),a6
	move.l	_IntuitionBase(a4),a1
	CALLSYS	CloseLibrary		;Close Intuition.library

.errout	tst.l	pr_CLI(a5)		;Started From WorkBench
	bne.s	.nowork
	bsr.s	.gework
	CALLSYS	Forbid
	move.l	a3,a1
	CALLSYS	ReplyMsg

.nowork	moveq	#0,d0
	rts
;-------------------------------------------------------------------------
; Data Area
;

	IFD	BACK
.protag	dc.l	NP_Entry,0		;Do NOT Change Order Of The Tags!!
	dc.l	NP_StackSize,0
	dc.l	NP_Priority
	IFND	PRI
	dc.l	0
	ELSE
	dc.l	PRI
	ENDC
	dc.l	NP_Name,_ProgramName
	dc.l	TAG_END
	ENDC

.bodstr	dc.b	-1,-1,0,0
	dc.w	14,14
	dc.l	0,.bodtxt,0

.negstr	dc.b	-1,-1,0,0
	dc.w	4,4
	dc.l	0,.negtxt,0

.bodtxt	dc.b	"You need Kickstart "
	IFD	KICKVER
	dc.b	KICKVER/10+48,KICKVER-(KICKVER/10*10)+48
	ELSE
	dc.b	"37"
	ENDC
	dc.b	" or higher to run this program.",0

.negtxt	dc.b	"ABORT",0

.dosnam	dc.b	"dos.library",0
.intnam	dc.b	"intuition.library",0

	IFD	UTILLIB
.utinam	dc.b	"utility.library",0
	ENDC

	IFD	WBARGS
.icnnam	dc.b	"icon.library",0
	ENDC
;-------------------------------------------------------------------------
; Background Process Startup
;

	IFD	BACK
	SECTION	text,CODE

.Main	lea	_LinkerDB,a4		;Base Register
	move.l	_SysBase(a4),a6
	lea	.DOSNAM(a4),a1
	moveq	#0,d0
	CALLSYS	OpenLibrary		;Open Dos Library
	move.l	d0,_DOSBase(a4)

	bsr	@main			;Call Main Function

	IFD	CLIARGS
	move.l	_DOSBase(a4),a6
	move.l	CliArg(a4),d1
	CALLSYS	FreeArgs		;Free CLI Arguments
	ENDC

	move.l	_SysBase(a4),a6
	IFD	UTILLIB
	move.l	_UtilityBase(a4),a1
	CALLSYS	CloseLibrary		;Close Utility.library
	ENDC

	move.l	_IntuitionBase(a4),a1
	CALLSYS	CloseLibrary		;Close Intuition.library

	move.l	_DOSBase(a4),a5
	move.l	a5,a1
	CALLSYS	CloseLibrary		;Close Dos.library

	move.l	a5,a6
	lea	.Main-4(pc),a0
	move.l	a0,d1
	lsr.l	#2,d1
	jmp	_LVOUnLoadSeg(a6)	;Free Program Memory
	ENDC
;-------------------------------------------------------------------------
	SECTION	__MERGED,DATA

.DOSNAM	dc.b	"dos.library",0
;-------------------------------------------------------------------------
	SECTION	__MERGED,BSS

	XDEF	_SysBase
	XDEF	_DOSBase
	XDEF	_IntuitionBase

_SysBase	ds.l	1
_DOSBase	ds.l	1
_IntuitionBase	ds.l	1

	IFD	UTILLIB
	XDEF	_UtilityBase
_UtilityBase	ds.l	1
	ENDC

	IFD	WBARGS
	XDEF	_IconBase
_IconBase	ds.l	1
	ENDC

	IFD	BACK
	IFD	CLIARGS
CliArg	ds.l	1
	ENDC
	ENDC

	IF	BACK1!NOCLI
NewStk		ds.l	1
StkLower	ds.l	1
StkUpper	ds.l	1
StkPointer	ds.l	1
	ENDC
;-------------------------------------------------------------------------
	END
