* RunBack.asm
*
*	Written 3/11/87
*
* Copyright (c) 1986 by C.Heath of Microsmiths Inc.
* This program may be freely distributed, but only in it's original
* unmodified state.  If you wish to distribute a modified version either
* commercially or otherwise, please contact:
*
*	Microsmiths, Inc
*	PO Box 561
*	Cambridge, MA 02140
*	(617)354-1224
*	bix: cheath  Compuserve: 74216,2117
*
*	This is the equivalent of Rob Peck's RunBackground program, with
* an addition of a command line Stack option, "-Snnnn".  See the readme
* file included with this ARC file for details.
*
******	Equates and publics	***************************************

	INCLUDE	"exec/types.i"
	INCLUDE	"libraries/dos.i"
	INCLUDE	"libraries/dosextens.i"

MIN_LIB		set	$1f		; Library minimum rev level!
					; ADOS "stack" command

MIN_STACK	set	1600		; Minimum stack allowed by the
					; ADOS "stack" command

*** NOTE: This was assembled with Manx V3.30E, but should be compatible
***	with MCC with minor changes.

xlib	macro	
	public	_LVO\1
	endm

	entry	.begin
	public	.begin
.begin

	xlib	OpenLibrary
	xlib	CloseLibrary
	xlib	FindTask

	xlib	Output
	xlib	Write

	xlib	Lock
	xlib	Examine
	xlib	UnLock
	xlib	CurrentDir
	xlib	ParentDir

	xlib	Open
	xlib	Close
	xlib	Delay
	xlib	Execute

******	The Program		***************************************

* Registers:
*	D6 is starting SP
*	D5 is execution delay
*	D4 is Save SP value
*		
*	A5 is p->CmdLineSwished
*	A4 is CLIStruct for Process Base
*	A3 is p_cmdname

Start:
	move.l	sp,D6			; Save stack pointer

	move.l	A0,A2			; Register A2 is cmdline henceforth
	clr.b	0(A2,D0.w)		; Make sure she be null terminado

	move.l	4,A6			; ExecBase in A6 until DOSBase
	suba.l	A1,A1
	jsr	_LVOFindTask(A6)
	move.l	D0,A4			; Process base
	move.l	pr_CLI(A4),D0
	 beq.s	BadExit			; Not a CLI process. Punt
	asl.l	#2,D0
	move.l	D0,A4			; A4 points at CLIStruct henceforth
	move.l	cli_DefaultStack(A4),D4	; D4 is Default Stack_a_Roo

	lea	DOSName(pc),A1		; Open DOS.library
	moveq.l	#MIN_LIB,d0
	jsr	_LVOOpenLibrary(A6)
	move.l	D0,A6
	or.l	D0,D0
	 bne.s	ok_start		; Continue if library OK,

* fall in to BadExit code if DOS library couldn't open

************************************************************************
*
* BadExit is where to go if there is an error opening the DOS library
*	This should only happen if things are really sick
*
************************************************************************
BadExit:	moveq	#20,D0
		rts

************************************************************************
*
* ok_start
*	Proceed with normal code, check the input string.
*
************************************************************************
ok_start:
	moveq	#0,D5			; Default delay value
*
* Process the input command string
*
skpspc:	move.b	(A2)+,D1		; Skip spaces 
	 beq.s	show_how		; Null string - give help!
	cmp.b	#$20,D1
	 beq.s	skpspc

	cmp.b	#$0a,D1
	 beq.s	show_how		; Help! Help!!!
	cmp.b	#'?',D1
	 beq.s	show_how		; Also a "?" asks for help!

	cmp.b	#'-',D1
	 beq.s	parse_opt		; Parse delay or stack option

* Here, A2 points at the command+1, D1 is first char
do_command:

* 256 is normally max cmdline size.
* But we add "run <nil:" stuff. Be safe.
* CAUTION: MAKE SURE SP IS STILL LONG_WORD ALLIGNED FOR ADOS!!!!!!!!!!!!!!!!
	sub	#292,sp			; Reserve space to build cmdline!

	move.l	sp,A5			; Space is reserved *here*
	lea	Erst(pc),A0		; Start cmd with "Run < >"
1$:	move.b	(A0)+,(A5)+
	 bne.s	1$
	subq	#1,A5			; Back up a char!

	move.l	A5,A3			; Save pointer to cmd_name
	move.b	#' ',D0
	cmp.b	#'"',D1
	 bne.s	do_cmd			; Check for Quoted string
	move	D1,D0			; Save terminator character!
	addq	#1,A3			; ADVANCE NAME PTR!!!!

do_cmd:
	move.b	D1,(A5)+		; Save the first char

	move.b	(A2),D1
	 beq.s	have_cmd		; EOS - leave A2-> EOS!
	cmp.b	#$0a,D1
	 beq.s	have_cmd		; Ditto.

	addq	#1,A2
	cmp.b	D0,D1
	 bne.s	do_cmd			; Loop till terminator

* Here, the command has been copied.  Add in "<nil: .nil:"
* BUT FIRST check for valid command!

have_cmd:
	move.b	D0,D3			; Save terminator damnit
	clr.b	(A5)			; Terminate the name, as command_name

	move.l	A3,D1
	move.l	#ACCESS_READ,D2
	jsr	_LVOLock(A6)		; Make sure the command exists-
	move.l	D0,D7			; Or ADOS WILL GURU! YEA! ADOS!
	 beq.s	nofile			; No File.  Belch!

	move.l	D0,D1
	sub	#fib_SIZEOF,sp
	move.l	sp,D2
	jsr	_LVOExamine(A6)

	move.l	D7,D1
	move.l	D0,D7
	jsr	_LVOUnLock(A6)
	tst	d7
	 beq.s	nofile			; Can't examine. Hmm...
	move.l	fib_DirEntryType(sp),D0
	 bge.s	nofile			; It's a dir. Fluff, Damnit.

* Adjusting the stack is only necessary since sp is used as cmd_base
* Othewise, it would be adjusted in Cleanup code.
	add	#fib_SIZEOF,sp

* OK!!! It's a file, and probably even loadable!
ok_cmd1:
	cmp.b	#'"',D3
	 bne.s	Really_AddNil
	move.b	D3,(A5)+

Really_AddNil:
	lea	Last(pc),A0		; Move the rest down
1$:	move.b	(A0)+,(A5)+
	 bne.s	1$
	move.b	#' ',-1(A5)		; OverWrite Null with Space

* Finally, copy any more of the command args
finis:	move.b	(A2)+,(A5)+
	 bne.s	finis

	move.l	#nilnam,D1
	move.l	#MODE_NEWFILE,D2
	jsr	_LVOOpen(A6)

	move.l	D0,D2
	move.l	D0,D3
	move.l	sp,D1
	jsr	_LVOExecute(A6)
	tst.l	D0
	 beq	NoRun

	lea	OKStart(pc),A0
	bsr.s	do_write

	move.l	D5,D1			; Delay by "this" much
	 ble.s	goodexit

	mulu	#60,D1
	jsr	_LVODelay(A6)		; Delay 60 ticks/second

	bra	goodexit

***************************************************************************
*
* parse_opt
*	Parse a stack or otherwise input paramter
*
***************************************************************************
parse_opt:
	moveq.l	#0,D1
	move.b	(A2)+,D1
	cmp.b	#'S',D1
	 beq.s	parse_stak	; Stack-size switch
	cmp.b	#'s',D1
	 beq.s	parse_stak	; Um, lower case, schmoer case.

	sub.b	#'0',D1
	 blt.s	bad_arg		; Must be 0..9 delay switch,
	cmp.b	#9,D1
	 bgt.s	bad_arg		; If not PUNT!

	move.l	D1,D5		; Save Delay option
	move.b	(A2)+,D1
	cmp.b	#' ',D1		; Must be followed by a SPACE
	 beq.s	skpspc		; OK, back to main cmdline loop
	bra.s	bad_arg

parse_stak:
*
* Here, loop to get input for new stack
* Loop getting Ascii digits
*
	moveq.l	#0,D0			; New Stack Value built into D0
1$:	moveq.l	#0,D1
	move.b	(A2)+,D1
	cmp.b	#' ',D1
	 beq.s	do_stak			; Terminate number on SPACE

	sub.b	#'0',D1
	 blt.s	bad_arg			; Test for valid digits
	cmp.b	#9,D1
	 bgt.s	bad_arg

	add.l	D0,D0
	move.l	D0,D2			; Multiply prior value by 10
	asl.l	#2,D2			; Required to allow long_word value
	add.l	D2,D0

	add.l	D1,D0			; Add in new digit
	bra.s	1$			; Loop on digits

do_stak: cmp.l	#MIN_STACK,D0
	 blt.s	bad_arg			; Match "stack" command

	lsr.l	#2,D0			; Convert to LWords
	move.l	D0,cli_DefaultStack(A4)
	bra	skpspc

***************************************************************************
*
* show_how
*	RBack was called with no arguement.  Just display instructions!
*
***************************************************************************
show_how:
	lea	str_usage(pc),A0
	bsr.s	do_write

goodexit:
	moveq	#0,D0
CleanUp:
	move.l	D4,cli_DefaultStack(A4),D4	; Restore default stack!

	move.l	D0,D2			; Save return value
	move.l	A6,A1
	move.l	4,A6			; AbsExecBase
	jsr	_LVOCloseLibrary(A6)

	move.l	D6,SP			; Restore initial SP
	move.l	D2,D0			; Restore return value
	rts				; and exit()

bad_arg:
	lea	BadArg(pc),A0
	bra.s	err_msg


***************************************************************************
*
* NoRun
*	Can't find c:Run, probably.  Close the nil: handle
*
***************************************************************************
NoRun:
	move.l	D2,D1
	jsr	_LVOClose(A6)		; Close the nil: file handle

	lea	CantStart(pc),A0

***************************************************************************
*
* err_msg
*	Merge point for some error messages.  Exits through cleanup
*
***************************************************************************
err_msg:
	bsr.s	do_write

	moveq	#10,D0			; Set to exit(10)
	bra.s	CleanUp

***************************************************************************
*
* do_write
*	Simple write string.
*
*	Assumes A6 = DOSBase
*	Null terminated string is @A0
*	Also assumes a reasonable CLI environment with valid COS
*
*	Zaps D0..D3/A0/A1
*
***************************************************************************
do_write:
	move.l	A0,D2
	moveq	#-1,D3
dwl1:	addq.l	#1,D3
	tst.b	(A0)+
	 bne.s	dwl1

do_writex:			; BCPL style entry with D2/D3 preset...
	jsr	_LVOOutput(A6)
	move.l	D0,D1
	jmp	_LVOWrite(A6)

***************************************************************************
*
* nofile
*	Here, the command can't be found!
*
***************************************************************************
nofile:
	lea	CantFind(pc),A0
	bsr	do_write

	move.l	A3,A0
	bsr	do_write

	lea	LFStr(pc),A0
	bra	err_msg

***************************************************************************
*
* Following is just constant data used by the program
*
***************************************************************************

DOSName:	dc.b	'dos.library',0

BadArg:
 dc.b 'Invalid parameter for RunBack!',$0a,$0a
str_usage:
 dc.b 'RunBack © 1987 by Microsmiths, Inc',$0a
 dc.b 'Usage: RunBack [-<loaddelay>] [-Snnnn] <name> [<parm(s)>]',$0a
 dc.b '     where optional loaddelay is 0-9 seconds,',$0a
 dc.b '     and Snnnn is an optional Stack size to set',$0a,0

Erst:		dc.b	'RUN >NIL: <NIL: ',0
Last		dc.b	' <NIL: >
nilnam:		dc.b	'NIL:',0

CantStart:	dc.b	"RunBack: Error starting background task!',$0a
		dc.b	"You must have the program 'Run' in your C: directory",$0a,0

CantFind:	dc.b	"Can't find ",0

OKStart:	dc.b	'Started background task'
LFStr:		dc.b	$0a,0

	END