;
; oscli.s
;
; OSCLI and system support for DLLs and clients
;
;  1994 Straylight
;

;----- Standard header ------------------------------------------------------

		GET	libs:swis
		GET	libs:header

;----- External dependencies ------------------------------------------------

		IMPORT	system
		IMPORT	|_kernel_system|
		IMPORT	|x$stack_overflow|

;----- Main code ------------------------------------------------------------

		AREA	|DLL$$Code|,CODE,READONLY

; --- _dll_system ---
;
; On entry:	a1 == pointer to command line string (passed to system)
; On exit:	a1 == return code, as for system()

		EXPORT	|_dll_system|
|_dll_system|	ROUT

		; --- Standard APCS bit on the top ---

		MOV	ip,sp			;Keep current stack pointer
		STMFD	sp!,{v1,v2,fp,ip,lr,pc}	;Create new stack frame
		SUB	fp,ip,#4		;Point fp at new stack frame
		CMP	sp,sl			;Is there enough stack?
		BLLT	|x$stack_overflow|	;No -- create some more

		; --- Preserve the old application handle ---

		MOV	v2,a1			;Preserve string pointer
		SWI	DLL_SaveHandle		;Get the current handle
		MOV	v1,a1			;Preserve its value

		; --- Call the actual command ---

		MOV	a1,v2			;Restore string pointer
		BL	system			;Do whatever it is we do

		; --- Restore the handle and exit ---

		MOV	v2,a1			;Keep hold of return value
		MOV	a1,v1			;Transfer old handle
		SWI	DLL_RestoreHandle	;Set up the handle again
		MOV	a1,v2			;Reinstate the return value
		LDMDB	fp,{v1,v2,fp,sp,pc}^	;Return to caller

		LTORG

; --- _dll_ksystem ---
;
; On entry:	R0 == pointer to command to execute
;		R1 == 0 to run as a subprocess, nonzero to replace
; On exit:	>=0 for success, <0 for failure

		EXPORT	|_dll_ksystem|
|_dll_ksystem|	ROUT

		; --- Standard APCS bit on the top ---

		MOV	ip,sp			;Keep current stack pointer
		STMFD	sp!,{v1,v2,fp,ip,lr,pc}	;Create new stack frame
		SUB	fp,ip,#4		;Point fp at new stack frame
		CMP	sp,sl			;Is there enough stack?
		BLLT	|x$stack_overflow|	;No -- create some more

		; --- Preserve the old application handle ---

		MOV	v2,a1			;Preserve string pointer
		SWI	DLL_SaveHandle		;Get the current handle
		MOV	v1,a1			;Preserve its value

		; --- Call the actual command ---

		MOV	a1,v2			;Restore string pointer
		BL	|_kernel_system|	;Do whatever it is we do

		; --- Restore the handle and exit ---

		MOV	v2,a1			;Keep hold of return value
		MOV	a1,v1			;Transfer old handle
		SWI	DLL_RestoreHandle	;Set up the handle again
		MOV	a1,v2			;Reinstate the return value
		LDMDB	fp,{v1,v2,fp,sp,pc}^	;Return to caller

		LTORG

; --- _dll_oscli ---
;
; On entry:	R0 == pointer to command string for OS_CLI
; On exit:	R0 == pointer to error, or 0

		EXPORT	|_dll_oscli|
|_dll_oscli|	ROUT

		MOV	ip,lr			;Keep link register
		MOV	a2,a1			;Keep pointer to string
		SWI	DLL_SaveHandle		;Get our current handle
		MOV	a3,a1			;Save it away
		MOV	a1,a2			;Restore pointer to command
		SWI	XOS_CLI			;Do the actual command
		MOVVS	a2,a1			;Save error ptr if it failed
		MOVVC	a2,#0			;Otherwise remember it worked
		MOV	a1,a3			;Restore the old handle
		SWI	DLL_RestoreHandle	;Resinstate the handle
		MOV	a1,a2			;Point at error block
		MOVS	pc,ip			;And return to caller

		LTORG

; --- _dll_starttask ---
;
; On entry:	R0 == pointer to command to run as a separate task
; On exit:	R0 == pointer to error, or 0

		EXPORT	|_dll_starttask|
|_dll_starttask| ROUT

		MOV	ip,lr			;Keep link register
		MOV	a2,a1			;Keep pointer to string
		SWI	DLL_SaveHandle		;Get our current handle
		MOV	a3,a1			;Save it away
		MOV	a1,a2			;Restore pointer to command
		SWI	XWimp_StartTask		;Do the actual command
		MOVVS	a2,a1			;Save error ptr if it failed
		MOVVC	a2,#0			;Otherwise remember it worked
		MOV	a1,a3			;Restore the old handle
		SWI	DLL_RestoreHandle	;Resinstate the handle
		MOV	a1,a2			;Point at error block
		MOVS	pc,ip			;And return to caller

		LTORG

;----- That's all, folks ----------------------------------------------------

		END
