;-------T-------T------------------------T------------------------------------------;
;Name:     StartDPK
;Template: StartDPK <TaskFile> [PREFS <Name>] <Arg1> <Arg2> ...
;Author:   Paul Manias
;Version:  V0.4
;Date:     September 1997
;Docs:     This program is intended to allow multi-platform capabilities by
;	   doing things like opening the kernel.  For example the following
;	   code would not work on a Mac even if it is 68000 code:
;
;	   move.l $4.w,a6
;	   ...
;	   CALL   OpenLibrary
;
;	   To fix this problem we put this machine-specific code in a task
;	   launcher (StartDPK) and pass the DPKBase onto the task.  Alakazam,
;	   multiple platform capabilities!
;
;PROBLEMS: Programs written in E cannot cope with this as far as I know :-(.

	INCDIR	"INCLUDES:"
	INCLUDE	"exec/exec_lib.i"
	INCLUDE	"exec/libraries.i"
	INCLUDE	"dos/dos_lib.i"
	INCLUDE	"dos/dosextens.i"
	INCLUDE	"workbench/startup.i"

	INCLUDE	"games/dpkernel.i"

CALL	MACRO
	jsr	_LVO\1(a6)
	ENDM

	SECTION	"StartDPK",CODE

;===================================================================================;
;                                INITIALISE PROGRAM
;===================================================================================;

Start:	MOVEM.L	D0-D7/A0-A6,-(SP)
	move.l	$4.w,a6
	move.l	a6,SysBase
	sub.l	a1,a1	;a1 = 0
	CALL	FindTask
	move.l	d0,a4
	tst.l	pr_CLI(a4)
	bne	.FromCLI

.FromWorkbench
	move.l	SysBase(pc),a6
	lea	DOSName(pc),a1
	moveq	#$00,d0
	CALL	OpenLibrary
	tst.l	d0
	beq	ExitToDOS
	move.l	d0,DOSBase	;a7 = DOSBase

	move.l	SysBase(pc),a6
	lea	pr_MsgPort(a4),a0
	CALL	WaitPort

	lea	pr_MsgPort(a4),a0
	CALL	GetMsg
	move.l	d0,WBenchMsg

	move.l	WBenchMsg(pc),a2	;a2 = WBenchMsg
	cmp.l	#2,sm_NumArgs(a2)	;a2 = Need at least 2 arguments.
	blt.s	ExitToDOS	;>> = Exit.
	tst.l	sm_ArgList(a2)	;a2 = Must have an argument list.
	beq.s	ExitToDOS	;>> = Exit.
	move.l	sm_NumArgs(a2),AmtArgs	;ma = Save amount of arguments.

	move.l	DOSBase(pc),a6	;a6 = DOSBase.
	move.l	sm_ArgList(a2),a0	;a0 = List of arguments.
	addq.w	#wa_SIZEOF,a0	;a0 = Second argument.

	move.l	wa_Lock(a0),d1	;d1 = Get the dir.
	CALL	CurrentDir	;>> = Go to that directory.

	;Get the file argument.

	move.l	sm_ArgList(a2),a0
	addq.w	#wa_SIZEOF,a0
	move.l	wa_Name(a0),TaskFile
	move.l	wa_Name(a0),CommandLine

	move.l	SysBase(pc),a6
	move.l	DOSBase(pc),a1
	CALL	CloseLibrary
	clr.l	DOSBase
	MOVEM.L	(SP)+,D0-D7/A0-A6
	bra.s	LaunchMain

.FromCLI
	MOVEM.L	(SP)+,D0-D7/A0-A6
	move.l	a0,CommandLine
	move.l	d0,AmtArgs

LaunchMain
	bsr.s	_Main	;>> = Call our program.

ExitToDOS:
	tst.l	WBenchMsg
	beq.s	.Exit	;>> = Exit if I was called from CLI.
	move.l	SysBase(pc),a6
	CALL	Forbid
	move.l	WBenchMsg(pc),a1
	CALL	ReplyMsg
.Exit	rts

;===================================================================================;
;                                     MAIN CODE
;===================================================================================;

_Main:	MOVEM.L	A0-A6/D0-D7,-(SP)
	move.l	SysBase(pc),a6
	lea	DOSName(pc),a1
	moveq	#$00,d0
	CALL	OpenLibrary
	move.l	d0,DOSBase
	beq.s	.Error_DOS

	lea	DPKName(pc),a1
	moveq	#$00,d0
	CALL	OpenLibrary
	move.l	d0,DPKBase
	beq.s	.Error_DPK

	cmp.l	#1,AmtArgs
	ble.s	.ReturnToDOS
	move.l	CommandLine(pc),a0
	cmp.b	#"?",(a0)
	bne.s	.go
	bsr.s	Usage
	bra.s	.ReturnToDOS

.go	bsr.s	ParseArguments
	tst.l	d0
	bne.s	.ReturnToDOS
	bsr	Launch
	bsr	FreeArguments

.ReturnToDOS
	move.l	DPKBase(pc),a6
	CALL	CloseDPK
.Error_DPK
	move.l	SysBase(pc),a6
	move.l	DOSBase(pc),a1
	CALL	CloseLibrary
.Error_DOS
	MOVEM.L	(SP)+,A0-A6/D0-D7
	moveq	#$00,d0
	rts

;===================================================================================;
;                             PRINT USAGE INFORMATION
;===================================================================================;

Usage:	move.l	DOSBase(pc),a6
	CALL	Output
	move.l	d0,d1	;d1 = File handle to write out to.
	move.l	#TXT_Usage,d2	;d2 = Pointer to buffered text.
	move.l	#TXT_UsageSize,d3	;d3 = Size of text.
	CALL	Write
	rts

;===================================================================================;
;                                 PARSE ARGUMENTS
;===================================================================================;
;Template is: StartDPK <TaskFile> [PREFS <Name>] <Arg1> <Arg2> ...

ParseArguments:
	tst.l	WBenchMsg
	beq.s	ParseCLI

ParseWorkBench:
	moveq	#$00,d0
	rts

ParseCLI:
	move.l	CommandLine(pc),a0	;a0 = Pointer to first char of <TaskFile>.
	cmp.l	#$00,a0
	beq.s	.Error_NoArgs

	moveq	#$00,d0	;d0 = Byte count of file name.
.loop	cmp.b	#10,(a0)	;a0 = Check for return key.
	beq.s	.key_return	;>> = Return key found.
	cmp.b	#' ',(a0)	;a0 = Check for space key.
	beq.s	.key_space	;>> = Return key found.
	addq.l	#1,d0	;d0 = ++1
	addq.w	#1,a0	;a0 = ++1
	bra.s	.loop	;>> = Keep looping till we find the end.

.key_return
	move.b	#' ',(a0)	;a0 = Replace return key with a space.
.key_space
	addq.l	#1,a0	;a0 = ++1
	move.l	a0,TaskArgs	;MA = Save pointer to DPK task args.
	move.l	SysBase(pc),a6	;a6 = ExecBase
	addq.l	#1,d0	;d0 = (MemSize)+1 [For null termination]
	move.l	d0,sizeTaskFile	;MA = Make a note of the size allocated.
	moveq	#$0,d1	;d1 = MemType
	CALL	AllocMem	;>> = AllocMem(Size:d0,Type:d1)
	move.l	d0,TaskFile	;MA = Pointer to file memory.
	beq.s	.Error_Memory	;>> = Memory error.
	move.w	#1,FreeTaskFile

	move.l	CommandLine(pc),a0	;a0 = Command Line source.
	move.l	TaskFile(pc),a1	;a1 = FileName destination.
.cloop	cmp.b	#" ",(a0)	;a0 = Check for space.
	beq.s	.done	;>> = Got it.
	move.b	(a0)+,(a1)+	;a1 = Copy Character++
	bra.s	.cloop	;>> = Keep looping.

.done	clr.b	(a1)+
	moveq	#$00,d0	;d0 = No errors.
	rts

.Error_Memory
	moveq	#ERR_NOMEM,d0	;d0 = Memory error.
	rts

.Error_NoArgs
	moveq	#ERR_ARGS,d0
	rts

FreeArguments:
	tst.w	FreeTaskFile
	beq.s	.done
	move.l	SysBase(pc),a6	;a6 = ExecBase.
	move.l	TaskFile(pc),a1	;a1 = Pointer to allocated block.
	move.l	sizeTaskFile(pc),d0	;d0 = Size of allocated block.
	CALL	FreeMem	;>> = Free it.
	clr.w	FreeTaskFile
	clr.l	TaskFile
.done	rts

;===================================================================================;
;                                LAUNCH DPK PROGRAM
;===================================================================================;
;Load the program in with LoadSeg() and then run it (remembering to pass the
;necessary variables).  On other machines this part will have to be modified to
;recognise and load in Amiga formatted file hunks.
;
;Sends: a0 = struct StartUp *;
;	d0 = LONG ID;

Launch:	move.l	DOSBase(pc),a6	;a6 = DOS Base.
	move.l	TaskFile(pc),d1	;d1 = Pointer to file name.
	CALL	LoadSeg	;>> = Go and load the executable.
	move.l	d0,Segment	;MA = Store pointer to segment.
	beq.s	.Error_Segment	;>> = Error loading file :-(

	;Initialise self-destruct sequence.

	move.l	DPKBase(pc),a6	;a6 = DPKBase.
	lea	.exit(pc),a0	;a0 = Pointer to SelfDestruct() cleanup.
	move.l	a7,a1	;a1 = Stack pointer.
	CALL	InitDestruct	;>> = Initialise the call.

	move.l	DPKBase(pc),a6
	moveq	#ID_STARTUP,d0
	CALL	Get
	move.l	d0,StartUp
	beq.s	.Error_StartUp

	lea	DPKTaskName(pc),a0	;a0 = Pointer to a name.
	CALL	SetUserPrefs	;>> = Set preferences.
	tst.l	d0	;d0 = Check for error.
	bne.s	.exit	;>> = Error, exit.

	;Setup parameters here.

	move.l	StartUp(pc),a0
	sub.l	a2,a2
	sub.l	a3,a3	;Clear all other registers before
	sub.l	a4,a4	;launching the task.
	sub.l	a5,a5
	sub.l	a6,a6
	moveq	#$00,d1
	moveq	#$00,d2
	moveq	#$00,d3
	moveq	#$00,d4
	moveq	#$00,d5
	moveq	#$00,d6
	moveq	#$00,d7

	move.l	Segment(pc),d0	;d0 = BCPL pointer to segment.
	add.l	d0,d0	;d0 = *2
	add.l	d0,d0	;d0 = *4
	move.l	d0,a1	;a2 = Pointer to start of seglist.
	move.l	#"DPKN",d0	;d0 = ID

	jsr	4(a1)	;>> = Start the DPK program.

.exit	move.l	DPKBase(pc),a6
	move.l	StartUp(pc),a0
	CALL	Free

.Error_StartUp
	move.l	DOSBase(pc),a6	;a6 = DOS Base.
	move.l	Segment(pc),d1	;d1 = BCPL segment pointer.
	CALL	UnLoadSeg	;>> = Unload the program.
.Error_Segment
	rts

;===================================================================================;
;                                       DATA
;===================================================================================;

DPKName:	dc.b  "GMS:libs/dpkernel.library",0
		even

DOSName:	dc.b  "dos.library",0
		even

DPKBase:	dc.l  0	;Pointer to DPKBase.
DOSBase:	dc.l  0

DPKTaskName:	dc.b  "Default",0
		even

StartUp:	dc.l  0
TaskFile:	dc.l  0	;Name of file to load.
FreeTaskFile:	dc.w  0
sizeTaskFile:	dc.l  0	;Size of allocated memory block.
Segment:	dc.l  0	;Pointer to segment of loaded file.
CommandLine:	dc.l  0	;Pointer to first command line argument.
AmtArgs:	dc.l  0	;Amount of arguments on command line.
TaskArgs:	dc.l  0	;Arguments for the DPK Task.
WBenchMsg:	dc.l  0
SysBase:	dc.l  0

TXT_Usage:
 dc.b	10
 dc.b	"STARTDPK",10
 dc.b	"--------",10
 dc.b	"This program will launch DPK tasks for you, and in future will",10
 dc.b	"be required for setting up programs that have been compiled on other",10
 dc.b	"platforms.",10
 dc.b	10
 dc.b	"To use it, just type:",10
 dc.b	10
 dc.b	"  1> StartDPK <FileName> <Arg1> <Arg2> <Arg3> ...",10
 dc.b	10
 dc.b	"Example:",10
 dc.b	10
 dc.b	"  1> StartDPK DPK:demos/Redimension",10
 dc.b	10
 dc.b	0

TXT_UsageSize = *-TXT_Usage

