*:ts=8
****************************************************************************
*									   *
* TINY.A				  (C) Copyright Eddy Carroll 1989  *
* ~~~~~~				  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  *
*									   *
* Replacement startup code for Lattice C V5.04. Use instead of c.o	   *
* This has many features stripped out to allow small utilities to have	   *
* as small a filesize as possible. In particular, don't call any of the    *
* stdio functions.							   *
*									   *
****************************************************************************

	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 "libraries/dos.i"
	INCLUDE "libraries/dosextens.i"
	INCLUDE "workbench/startup.i"
	INCLUDE "exec/funcdef.i"
	INCLUDE "exec/exec_lib.i"
	INCLUDE "libraries/dos_lib.i"

MAXARGS	    EQU 100	; Maximum number of command line arguments from CLI
AbsExecBase EQU 4	; Welcome to the only fixed point in the universe

* A useful macro to let us call library routines
callsys macro
	CALLLIB _LVO\1
	endm

	xdef	XCEXIT
	xdef	exit
	xref	LinkerDB
	xref	_BSSBAS
	xref	_BSSLEN

	csect	text,0,0,1,2		* xref's after this are 16-bit reloc
	xref	main			* Name of C program to start with.

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

	suba.l	a1,a1
	callsys	FindTask		* Find out our task ID
	move.l	d0,a3

	move.l	a5,D0	  		* get top of stack
	sub.l	4(a5),D0		* compute bottom
	add.l	#128,D0 		* allow for parms overflow
	move.l	D0,_base(A4)		* save for stack checking

	lea	DOSName(A4),A1
	moveq.l	#0,D0
	callsys	OpenLibrary
	move.l	D0,DOSBase(A4)
	bne	getcom
noDOS:
	moveq.l #100,d0
	bra	exit2

*------ find command name:
getcom:
	move.l  pr_CLI(a3),a0
	add.l	a0,a0
	add.l	a0,a0
	move.l	cli_CommandName(a0),a1
	add.l	a1,a1
	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,_ProgramName(A4)
	add.l	d1,d0			* add length of command name
	addq.l	#1,d0			* allow for space after command

	clr.w	-(A7)			* set null terminator for command line
	addq.l	#1,D0			* force to even number of bytes
	andi.w	#$fffe,D0		* (round up)
	sub.l	D0,A7			* make room on stack for command line
	subq.l	#2,D0
	clr.w	0(A7,D0)

*------ copy command line onto stack
	move.l	d2,d0			* get command line length
	subq.l	#1,d0
	add.l	d1,d2

copy_line:
	move.b	0(A2,D0.W),0(A7,D2.W)	* copy command line to stack
	subq.l	#1,d2
	dbf	d0,copy_line
	move.b	#' ',0(a7,d2.w) 	* add space between command and parms
	subq.l	#1,d2

copy_cmd:
	move.b	0(a1,d2.w),0(a7,d2.w)	* copy command name to stack
	dbf	d2,copy_cmd
	move.l	a7,a1			* Get pointer to new command line

	sub.l	#(MAXARGS*4),a7		* Reserve space for argv[]
	move.l	a7,a2			* Initialise base into array
	move.l	a2,a3			* Save base of argv
	moveq	#0,d2			* Initialise argc

*
* From here on down, A1 is pointer into command line
*
build_argv:
	bsr.s	getnext			* Read next character from line
	bcs.s	doquote			* If quote, handle
	beq.s	build_argv		* If white space, skip over it

	lea	-1(a1),a0		* Get address of this parameter
	bsr.s	bumpargv		* Store it to argv[] array
build_2:
	bsr.s	getnext			* Get next character
	bne.s	build_2			* If not white space, keep looking
	clr.b	-1(a1)			* Zero-terminate current argument
	bra.s	build_argv		* And go back to get next argument

doquote:
	move.l	a1,a0			* Get pointer to this argument
	bsr.s	bumpargv		* Output it to argv[]
quote_2:
	bsr.s	getnext			* Get next character
	bcc.s	quote_2			* If not quote, keep looking
	clr.b	-1(a1)			* Zero-terminate current argument
quote_3:
	bsr.s	getnext			* Get next character
	bne.s	quote_3			* Skip until space reached
	beq.s	build_argv		* Go back and read next argument

bumpargv:
	move.l	a0,(a2)+		* Output ptr to current argument
	addq	#1,d2			* Increment argc
	cmpi	#MAXARGS,d2		* Used up all our arguments yet?
	bls.s	qrts			* If not, then return
	moveq	#110,d0			* Else set return code
	bra.s	exit2			* And exit

*
* Reads next character from command line. If zero, never returns, but
* drops into call to main. Else, returns, with C=1 if character is quote,
* Z=1 if character is white space.
*
getnext:
	move.b	(a1)+,d0		* Get character from command line
	beq.s	get_2			* Exit if end of line
	cmp.b	#34,d0			* Check if quote
	beq.s	isquote			*
	cmp.b	#32,d0			* Check if space
	beq.s	isspace			*
	cmp.b	#9,d0			* Or tab
	beq.s	isspace			*
	cmp.b	#10,d0			* Or end of line
isspace:
	andi	#$1E,ccr		* Clear carry flag, retaining Z
qrts	rts

isquote:
	ori	#1,ccr			* Set carry flag
	andi	#$FB,ccr		* Clear zero flag
	rts				* And return

get_2:
	move.l	a3,-(a7)		* Push argv onto stack
	move.l	d2,-(a7)		* Push argc onto stack

	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

domain:
	jsr	main(PC)		* Call main(argc,argv)
	moveq.l #0,d0			* Set successful status
	bra.s	exit2

exit:
_exit:
XCEXIT:
	move.l	4(SP),d0		* Extract return code
exit2:
	move.l	d0,-(a7)
	move.l	AbsExecBase.W,a6
	move.l	DOSBase(A4),a1
	callsys CloseLibrary		* Close Dos library

*------ this rts sends us back to DOS:
exitToDOS:
	MOVE.L	(A7)+,D0
	movea.l _StackPtr(a4),SP	* Restore stack ptr
	movem.l (a7)+,d1-d6/a0-a6
	rts

*-----------------------------------------------------------------------
* Global definitions
*
	csect	__MERGED,1,,2,2

	xdef	NULL,SysBase,LoadAddress,DOSBase
	xdef	_oserr,_OSERR,_ONBREAK
	xdef	_ProgramName,_StackPtr,_base

NULL	       dc.l    0
_base	       dc.l    0
_oserr	       equ     *
_OSERR	       dc.l    0
_ONBREAK       dc.l    0
SysBase        dc.l    0
LoadAddress    dc.l    0
_StackPtr      dc.l    0
DOSBase        dc.l    0
_ProgramName   dc.l    0
DOSName        dc.b    'dos.library',0

	END
