*
** Startup.Easy v1.1
*
** Author: Jörg van de Loo
**         Hövel 15
**         47559 Kranenburg
**         Germany
** ...this material was written using HiSoft's "Devpac Assembler 3".
*
** This  file  is  FreeWare (I would say public domain but this gives criminal
** people the right to add "their" copyright remark, so to protect myself from
** excluding  of  the  use  of  this  startup-code,  it's FreeWare and I'm the
** copyright holder).
** HiSoft  (UK) is it allowed to use/spread/include this file if they like to,
** also in modified form, for free.
*
** Date: 5.21.1993
*
** I  cannot  be  held  for  any  failures may happen using this startup-code.
** Unnecessary to tell that you use it at your own risk.
*

*
** This  startup-code  is  reentrant,  so  if your code is it too, you may use
** Shell command "Resident".
*

*
** The  BaseTable is only readable!  Don't go messing with 'em or weird things
** may happen.
*

*
** The BaseTable used by this startup-code is 68 bytes large.  If you define a
** label  called  "_TableSize"  before  you  include  the  startup-code  (it's
** important!)  then  you  can  specify the bytesize of the table on your own,
** e.g.  1024 bytes.  Up from offset 68 you can now store your own datas,
** e.g. _GfxBase.
*
** Note:   This  startup-code  offers only 32KB of datas that can be reached -
**	   BSS relative to A5.
*

*
** Example:
**
*	STRUCTURE	mytable,68	; begin at offset 68
*	APTR		_GfxBase	; offset 68
*	APTR		_IntuitionBase	; offset 72
*	UBYTE		_myFlag		; offset 76
*	LABEL		_TableSize
*		; size for "BaseTable" and! "mytable" (here 77 bytes) -
*		; automatically allocated when startup-code is executed.
*
*	include		include/startup.easy	; insert startup-code
*
* _main		; this label is the entry point for your code!
*	....
*	....
*
**
** The  label  "_main" will be called out of the startup-code.  There your own
** code has to start.
** When  your code returns to the exit-routine, all things allocated/opened by
** the startup-code are freed/closed.
* 
** The  address  register  where  the  BaseTable  is  stored, is the processor
** register A5.  Now you can store/read constants out of it, e.g.
*
*	movea.l	_DOSBase(A5),A6			; get base of dos-lib
*

*
** To exit your code there are different ways.
*
**  1. By "RTS"				stack must be ok!
**  2. By calling "bsr _exit" 		no need for corrected stack
**  3. By calling "bra _exit" 		ditto
**  4. By calling "jsr _exit" 		ditto
**  5. By calling "jmp _exit" 		ditto
*
** It's not necessary to restore the stack nor to restore the A5 register when
** using exits 2,3,4,5.
*

*
** This  startup-code  is  a  thined  version  of  a  startup-code which I use
** normally.   Because  I  wrote a few programs for the PD and I don't want to
** spread  my  hard  worked made startup-code (it's a lot time better than the
** original of Commodore), I wrote this one.
*


	IFND	STARTUP_EASY
STARTUP_EASY	SET	1

*	incdir	:include/
	IFND	EXEC_TYPES_I
	include	exec/types.i
	ENDC

	IFND	EXEC_MEMORY_I
	include	exec/memory.i
	ENDC

	IFND	EXEC_TASKS_I
	include	exec/tasks.i
	ENDC

	IFND	EXEC_LIBRARIES_I
	include	exec/libraries.i
	ENDC

	IFND	CALLEXEC
	include	exec/exec_lib.i
	ENDC

*	include	exec/execbase.i

	IFND	CALLDOS
	include	dos/dos_lib.i
	ENDC

	IFND	DOS_DOSEXTENS_I
	include	dos/dosextens.i
	ENDC

	IFND	WORKBENCH_STARTUP_I
	include	workbench/startup.i
	ENDC

*	include	workbench/icon_lib.i

	IFND	WORKBENCH_WORKBENCH_I
	include	workbench/workbench.i
	ENDC


	IFND	AbsExecBase
AbsExecBase	EQU	4
	ENDC

	IFND	ThisTask
ThisTask		EQU	276
	ENDC

	IFND	_LVOGetDiskObject
_LVOGetDiskObject	EQU	-78
	ENDC

	IFND	_LVOFreeDiskObject
_LVOFreeDiskObject	EQU	-90
	ENDC



StoreTableSize	MACRO
	IFND	 _TableSize
	move.l	#256,D0		; Default, if nothing is specified

	ELSE

	IFLE	_TableSize-127	; If _TableSize < 128 use moveq
	moveq	#_TableSize,D0

	ELSE

	IFLE	_TableSize-32767 ; _TableSize not larger than 32KB
	move.l	#_TableSize,D0

	ELSE
	FAIL	<BSS-table exeeds 32KB!> ; else tell user
	ENDC

	ENDC
	ENDC

	addq.l	#7,D0		; ...make size divisible
	andi.l	#-8,D0		; through eight -> for exec's AllocMem()...
	ENDM



*
** This is the BaseTable....
*
   STRUCTURE	BaseTable,0	; begin at offset NULL
	APTR	bt_Reserved0	; currently unused - do not use!
	APTR	_SysBase	; pointer to exec-base (readable)
				; NOTE: « movea.l _SysBase.w,A6 » still work
	APTR	bt_Reserved1	; currently unused - do not use!
	APTR	bt_Reserved2	; currently unused - do not use!
	APTR	_DOSBase	; pointer to dos-base (opened/readable)
	APTR	_IconBase	; pointer to icon-base (readable, may not opened)
	APTR	_argv		; pointer to dos/WB-arguments (readable, may NULL)
	ULONG	_argc		; numbers of dos/WB-arguments (readable, may NULL)
	APTR	_OwnTask	; pointer to own-process-structure (readable)
	APTR	_OwnName	; pointer to own-program-name
				; (readable, Shell: with path, WB: name only)
	ULONG	_CmdNameSize	; PRIVATE!!!
	APTR	_WBenchMsg	; pointer to Workbench-message (readable, may NULL)
	APTR	_ToolTypesArray	; pointer to tooltypes (readable, may NULL)
	APTR	_OwnDiskObject	; pointer to own-program-icon-structure (readable,
*				  may NULL)
	APTR	_stdin		; pointer to standard output-handle (readable,
*				  may NULL)
	APTR	_stdout		; pointer to standard input-handle (readable,
*				  may NULL)
	ULONG	_errno		; place into this constant the returncode of
*				  your program
	LABEL	bt_SIZEOF	; size of this table: 68 bytes - next free offset: 68!

*
** Where  "may NULL" stands it's possible that this values are not initialized
** if running from Workbench or when running from Shell.
*
* Examples: The WBenchMsg will be NULL if running under Shell.
*	    The stdin or stdout will be NULL when running from Workbench.
*	    So watch out!


_startup
	movem.l	D0/A0,-(sp)

	move.l	AbsExecBase.w,A6
	StoreTableSize			; MACRO - bytesize of "_TableSize"
	move.l	#MEMF_PUBLIC|MEMF_CLEAR,D1
	jsr	_LVOAllocMem(A6)	; Allocate BaseTable and user's BSS
	tst.l	D0
	beq.w	__noTable
	movea.l	D0,A5			; Pointer to BaseTable into A5
	move.l	A6,_SysBase(A5)

	move.l	(sp)+,_argc(A5)		; Number of chars in commandline
	move.l	(sp)+,_argv(A5)		; Address commandline (if Shell)

	move.l	A5,-(sp)		; Save BaseTable right in front
*					  of ReturnAddr of task

	cmpi.w	#32,LIB_VERSION(A6)	; Say: I need at least kickstart 1.2
	bls.w	__fastout

	lea	_DOSName(pc),A1
	moveq	#0,D0			; Say: any version up from  Kickstart 1.2
	jsr	_LVOOpenLibrary(A6)
	move.l	D0,_DOSBase(A5)
	beq.w	__fastout		; ...only for savety...

	sub.l	A1,A1
	jsr	_LVOFindTask(A6)
	move.l	D0,_OwnTask(A5)		; Pointer to process-structure

	movea.l	D0,A2
	tst.l	pr_CLI(A2)		; Are we called from CLI or WBench?
	bne.s	.fromDOS

* ...it was Workbench
	lea	pr_MsgPort(A2),A0
	jsr	_LVOWaitPort(A6)	; Wait for WB-message

	lea	pr_MsgPort(A2),A0
	jsr	_LVOGetMsg(A6)		; Get message
	move.l	D0,_WBenchMsg(A5)	; and save message for later

	movea.l	D0,A0			; Message
	move.l	sm_NumArgs(A0),_argc(A5) ; Number of files
	move.l	sm_ArgList(A0),_argv(A5) ; Array of locks and files

	lea	_IconName(pc),A1
	moveq	#33,D0
	jsr	_LVOOpenLibrary(A6)	; Open Icon-library
	move.l	D0,_IconBase(A5)
	beq.s	.skipToolTypes

	tst.l	_argv(A5)		; Array empty?
	beq.s	.skipToolTypes
	movea.l	_argv(A5),A0		; Array of:
*	lock[0],file[0], lock[1],file[1], lock[2],file[2] and so on
	move.l	(A0),D1			; wa_Lock(A0),D1 (home-lock)
	beq.s	.skipLock
	movea.l	_DOSBase(A5),A6
	jsr	_LVOCurrentDir(A6)	; Change directory to PROGDIR
	tst.l	D0
	bmi.s	.skipToolTypes
.skipLock
	movea.l	_IconBase(A5),A6
	movea.l	_argv(A5),A0
	movea.l	wa_Name(A0),A0		; Our name...
	move.l	A0,_OwnName(A5)		; Remember name of prg
	jsr	_LVOGetDiskObject(A6)	; Read program-icon
	tst.l	D0
	beq.s	.skipToolTypes
	move.l	D0,_OwnDiskObject(A5)	; Remember icon-structure of our prg
	movea.l	D0,A0
	move.l	do_ToolTypes(A0),_ToolTypesArray(A5)
.skipToolTypes
	bra.s	__main

* ...Shell start...
.fromDOS
	movea.l	_DOSBase(A5),A6
	jsr	_LVOInput(A6)
	move.l	D0,_stdin(A5)
	jsr	_LVOOutput(A6)
	move.l	D0,_stdout(A5)

	movea.l	_OwnTask(A5),A0
	movea.l	pr_CLI(A0),A0
	adda.l	A0,A0
	adda.l	A0,A0
	movea.l	cli_CommandName(A0),A2	; BSTR to our prg-name
	adda.l	A2,A2
	adda.l	A2,A2			; APTR
	moveq	#0,D2
	move.b	(A2)+,D2		; Get length of our name

	move.l	#103,_errno(A5)		; Setup possible error

	move.l	D2,D0			; Length
	addq.w	#8,D0			; plus 1 byte (NULL-byte) plus 7 &
	andi.w	#-8,D0			; "and" with -8 =  make length divisible through 8
	move.l	D0,_CmdNameSize(A5)	; Remember size for later
	move.l	#MEMF_PUBLIC|MEMF_CLEAR,D1
	movea.l	_SysBase(A5),A6
	jsr	_LVOAllocMem(A6)	; Allocate name-buffer
	move.l	D0,_OwnName(A5)		; Save pointer to name-buffer
	beq.s	__closeAndFree

	clr.l	_errno(A5)		; Tell: no error occurred

	movea.l	D0,A0			; Name-buffer
	bra.s	.doIt			; Because of DBF
.StoreName
	move.b	(A2)+,(A0)+		; Copy CMD-name into own buffer
.doIt
	dbf	D2,.StoreName
	clr.b	(A0)			; Not needed....
__main
	move.l	_SysBase(A5),A6
	bsr.w	_main			; Call user's code with:
*					  ·A5 BaseTable, A6 SysBase·

_exit
	movea.l	AbsExecBase.w,A6	; Execbase
	suba.l	A1,A1			; 0 = own task (process)
	jsr	_LVOFindTask(A6)	; Find our process
	movea.l	D0,A0			; Pointer to A0
	movea.l	pr_ReturnAddr(A0),A0	; Program's exit address
	subq.l	#8,A0
	move.l	A0,sp			; Correct Stackpointer
	move.l	(sp)+,A5		; Place basetable pointer in A5
*					  and make a "RTS" using right address

	tst.l	_WBenchMsg(A5)
	beq.s	.fromDOS

	tst.l	_IconBase(A5)
	beq.s	.ReplyMsg

	tst.l	_OwnDiskObject(A5)
	beq.s	.ReplyMsg
	movea.l	_OwnDiskObject(A5),A0
	movea.l	_IconBase(A5),A6
	jsr	_LVOFreeDiskObject(A6)	

.ReplyMsg
	movea.l	_SysBase(A5),A6
	tst.l	_IconBase(A5)
	beq.s	.skipIt
	movea.l	_IconBase(A5),A1
	jsr	_LVOCloseLibrary(A6)
.skipIt
	jsr	_LVOForbid(A6)

	movea.l	_WBenchMsg(A5),A1
	jsr	_LVOReplyMsg(A6)

	bra.s	__closeAndFree

.fromDOS
	movea.l	_SysBase(A5),A6
	move.l	_CmdNameSize(A5),D0
	movea.l	_OwnName(A5),A1
	jsr	_LVOFreeMem(A6)

__closeAndFree
	move.l	_errno(A5),D2
	movea.l	_DOSBase(A5),A1
	movea.l	_SysBase(A5),A6
	jsr	_LVOCloseLibrary(A6)
	movea.l	_OwnTask(A5),A2
	movea.l	A5,A1
	StoreTableSize
	jsr	_LVOFreeMem(A6)	
	move.l	D2,D0
	move.l	D0,pr_Result2(A2)	; Back to  Shell/WB with returncode in D0
	rts				; and a valid Result2 constant...

* ------------------------------------- *
__noTable
	addq.w	#8,sp
	moveq	#103,D0
	move.l	ThisTask(A6),A0
	move.l	D0,pr_Result2(A0)
	rts
__fastout
	movea.l	A5,A1
	StoreTableSize
	jsr	_LVOFreeMem(A6)	
	moveq	#121,D0
	move.l	ThisTask(A6),A0
	move.l	D0,pr_Result2(A0)
	rts
_DOSName
	dc.b	'dos.library',0
_IconName
	dc.b	'icon.library',0

	CNOP	0,4

	ENDC
* ------------------------------------- *
