;
; misc.s
;
; Miscellaneous things for DLL Manager
;
;  1994-1998 Straylight
;

;----- Licensing note -------------------------------------------------------
;
; This file is part of Straylight's Dynamic Linking System (SDLS)
;
; SDLS is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 2, or (at your option)
; any later version.
;
; SDLS is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with SDLS.  If not, write to the Free Software Foundation,
; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

;----- Standard stuff -------------------------------------------------------

		GET	libs:header
		GET	libs:swis

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

		GET	sh.wSpace

		GET	sh.messages

;----- Some magic numbers ---------------------------------------------------

misc_entkrnl	EQU	4*48			;48 kernel entries
misc_entclib	EQU	4*183			;183 CLib entries
misc_wspkrnl	EQU	&31C			;&31C bytes of kernel vars
misc_wspclib	EQU	&B48			;&B48 bytes of clib vars
misc_clibVer	EQU	5			;Current CLib version

;----- External routines ----------------------------------------------------

		AREA	|DLLM$$Code|,CODE,READONLY

; --- misc_getCLib ---
;
; On entry:	--
; On exit:	--

		EXPORT	misc_getCLib
misc_getCLib	ROUT

		BIC	R14,R14,#V_flag		;Clear error indicator
		STMFD	R13!,{R1-R6,R14}	;Store registers nicely

		; --- Allocate workspace for SharedCLibrary to corrupt ---
		;
		; The SharedCLibrary wants some workspace that it can
		; initialise.  We're not actually using it, so we don't need
		; any workspace, although it still wants some.  So we
		; allocate some for a bit, and get rid of it again.

		MOV	R0,#6			;Allocate space for CLib
		LDR	R4,=misc_wspkrnl	;Amount of space for kernel
		LDR	R5,=misc_wspclib	;Amount of space for C lib
		ADD	R3,R3,#1024		;Add an extra 1K for luck
		ADD	R3,R4,R5		;Amount of space reqd
		SWI	XOS_Module		;Try to allocate memory
		LDMVSFD	R13!,{R1-R6,PC}		;Return if it failed

		; --- Set up stub table temporarily on the stack ---

		SUB	R13,R13,#44		;Reserve space for stub table
		MOV	R0,R13			;Point to base of table
		STR	R2,[R0,#12]		;Store workspace pointer
		ADD	R2,R2,R4		;Limit of kernel space
		STR	R2,[R0,#16]		;Store workspace pointer
		STR	R2,[R0,#32]		;Store as Clib pointer
		ADD	R2,R2,R5		;Limit of C lib space
		STR	R2,[R0,#36]		;Store as C lib limit

		; --- Set up pointers to branch table in the stub block ---

		ADR	R2,misc__stubs		;Point to entry point table
		LDR	R4,=misc_entkrnl	;Get size of kernel entries
		LDR	R5,=misc_entclib	;Get size of C lib entries
		STR	R2,[R0,#4]		;Store kernel entry start
		ADD	R2,R2,R4		;Limit of kernel entries
		STR	R2,[R0,#8]		;Store kernel entry limit
		STR	R2,[R0,#24]		;Store C lib entry start
		ADD	R2,R2,R5		;Limit of C lib entries
		STR	R2,[R0,#28]		;Store C lib entry limit

		; --- Finish off the stub table ---

		MOV	R2,#1			;Kernel chunk ID
		STR	R2,[R0,#0]		;Store in correct place
		MOV	R2,#2			;C lib chunk ID
		STR	R2,[R0,#20]		;Store in correct place
		MOV	R2,#-1			;Chunk table end marker
		STR	R2,[R0,#40]		;Store at end of table

		; --- Get the branch table from the C Library ---

		LDR	R1,[R0,#36]		;Get limit of that space
		ADD	R2,R1,#1024		;Point to end of block
		MOV	R3,#-1			;No zero-inited space
		MOV	R4,#0			;No static data to move
		MOV	R5,#-1			;No static data to move
		MOV	R6,#&1000		;4096 byte stack please :-)
		SWI	XSharedCLibrary_LibInitModule ;Do the stuff
		ADRVSL	R5,msg_errNoCLib	;If it failed, point to err
		MOVVC	R5,#0			;Otherwise, clear error mark

		; --- Tidy up the stack and the temporary space ---

		MOV	R0,#7			;Free that memory I nabbed
		LDR	R2,[R13,#12]		;Get pointer to the space
		ADD	R13,R13,#44		;Move stack pointer back
		SWI     XOS_Module		;Free it now
		LDMVSFD	R13!,{R1-R6,PC}		;If that failed, return error
		MOVS	R0,R5			;Copy error pointer
		LDMNEFD	R13!,{R1-R6,R14}	;If there was an error, unstk
		ORRNES	PC,R14,#V_flag		;And quit with V set

		; --- Make sure the library was new enough ---

		CMP	R6,#misc_clibVer	;Ensure returned version
		ADRLTL	R0,msg_errOldCLib	;If too low, point to error
		LDMFD	R13!,{R1-R6,R14}	;Get registers anyway
		ORRLTS	PC,R14,#V_flag		;If too old, quit with V set
		BICS	PC,R14,#V_flag		;Otherwise, clear V flag

		LTORG

; --- misc_copyStubs ---
;
; On entry:	R0 == pointer to stubs table
; On exit:	--

		EXPORT	misc_copyStubs
misc_copyStubs	ROUT

		STMFD	R13!,{R0-R3,R14}	;Preserve registers
		ADR	R1,misc__stubs		;Get pointer to stub table

		LDR	R14,[R1,#0]		;Load the first entry
		CMP	R14,#0			;Has it been filled in?
		BLEQ	misc_getCLib		;No -- find C library stuff
		BVS	%80misc_copyStubs	;If it failed, return error

		LDR	R0,[R13],#4		;Load branch table pointer
		LDR	R2,=misc_entkrnl+misc_entclib ;Get size of table
		SUB	R3,R1,R0		;Find ptr_diff 'tween tables
		MOV	R3,R3,LSR #2		;Shift off bottom two 0 bits

		SUBS	R2,R2,#4		;Decrement counter for table
00misc_copyStubs
		LDR	R14,[R1,R2]		;Get the word from the table
		ADD	R14,R14,R3		;Relocate to destination
		BIC	R14,R14,#&FF000000	;Clear some bits, for safety
		ORR	R14,R14,#&EA000000	;Add on the opcode nicely
		STR	R14,[R0,R2]		;Store in destination table
		SUBS	R2,R2,#4		;Decrement counter for table
		BGE	%00misc_copyStubs	;Continue if anything left

		LDMFD	R13!,{R1-R3,R14}	;Return if complete
		BICS	PC,R14,#V_flag		;Return with no errors

80misc_copyStubs
		ADD	R13,R13,#4		;Don't restore R0
		LDMFD	R13!,{R1-R3,R14}	;Restore registers
		ORRS	PC,R14,#V_flag		;And return with V set

		LTORG

; --- misc_strcmp ---
;
; On entry:	R0 == pointer to string A
; 		R1 == pointer to string B
;		R2 == 0 => case insensitive, 1 => case sensitive
;
; On exit:	Flags as appropriate
;
; Recently bodged to allow space-separated strings, which CLIGuard approves
; of more.

		EXPORT	misc_strcmp
misc_strcmp	ROUT

		STMFD	R13!,{R0,R1,R3,R4,R14}
00misc_strcmp	LDRB	R3,[R0],#1		;Get a character from A
		LDRB	R4,[R1],#1		;And one from B

		CMP	R2,#0			;Do we want to do case xlate?
		BNE	%10misc_strcmp		;No -- miss it out then

		SUB	R14,R3,#'a'		;Subtract the bottom limit
		CMP	R14,#26			;Is it a lower case letter?
		BICLO	R3,R3,#&20		;Yes -- convert to upper
		SUB	R14,R4,#'a'		;Subtract the bottom limit
		CMP	R14,#26			;Is it a lower case letter?
		BICLO	R4,R4,#&20		;Yes -- convert to upper

10misc_strcmp	CMP	R3,#&21			;Is that the end of A?
		MOVCC	R3,#0			;Yes -- pretend it's null
		CMP	R4,#&21			;Is that the end of B?
		MOVCC	R4,#0			;Yes -- pretend it's null

		CMP	R3,R4			;How do they match up?
		LDMNEFD	R13!,{R0,R1,R3,R4,PC}	;If NE, return condition
		CMP	R3,#0			;Is this the end?
		BNE	%00misc_strcmp		;No -- loop again
		LDMFD	R13!,{R0,R1,R3,R4,PC}	;Return to caller

		LTORG

; --- misc_memcpy ---
;
; On entry:	R0 == pointer to destination
;		R1 == pointer to source
;		R2 == length to copy
; On exit:	--

		EXPORT	misc_memcpy
misc_memcpy	ROUT

		STMFD	R13!,{R1-R9,R14}	;Stack registers

		; --- Do the fast copy of most of the data ---

00misc_memcpy	SUBS	R2,R2,#32		;Check there's 32 bytes left
		LDMGEIA	R1!,{R3-R9,R14} 	;Load 8 words (32 bytes)
		STMGEIA	R0!,{R3-R9,R14} 	;And store in workspace
		BGE	%00misc_memcpy		;Try for another one

		; --- Now do a word-by-word copy ---

		ADD	R2,R2,#32		;Reinstate the byte count
01misc_memcpy	SUBS	R2,R2,#4		;Check there's 4 bytes left
		LDRGE	R14,[R1],#4		;Load 1 word (4 bytes)
		STRGE	R14,[R0],#4		;And store in workspace
		BGE	%01misc_memcpy		;Try for another one

		LDMFD	R13!,{R1-R9,PC}^	;Return to caller

		LTORG

; --- misc_zinit ---
;
; On entry:	R0 == pointer to base of area
;		R1 == pointer to limit
; On exit:	--

		EXPORT	misc_zinit
misc_zinit	ROUT

		STMFD	R13!,{R1-R8,R14}	;Stack registers

		; --- Set up *lots* of zeroes ---

		MOV	R2,#0
		MOV	R3,#0
		MOV	R4,#0
		MOV	R5,#0
		MOV	R6,#0
		MOV	R7,#0
		MOV	R8,#0
		MOV	R14,#0

		; --- Do the fast copy of most of the data ---

		SUB	R1,R1,R0		;Convert limit to length

00misc_zinit	SUBS	R1,R1,#32		;Check there's 32 bytes left
		STMGEIA	R0!,{R2-R8,R14} 	;And store in workspace
		BGE	%00misc_zinit		;Try for another one

		; --- Now do a word-by-word copy ---

		ADD	R1,R1,#32		;Reinstate the byte count
01misc_zinit	SUBS	R1,R1,#4		;Check there's 4 bytes left
		STRGE	R14,[R0],#4		;And store in workspace
		BGE	%01misc_zinit		;Try for another one

		LDMFD	R13!,{R1-R8,PC}^	;Return to caller

		LTORG

; --- misc_strcpy ---
;
; On entry:	R0 == destination string
; 		R1 == source string
; On exit:	R0 == pointer to terminator of destination

		EXPORT	misc_strcpy
misc_strcpy	ROUT

		STMFD	R13!,{R1,R14}		;Keep return address safe
00misc_strcpy	LDRB	R14,[R1],#1		;Get a byte from source
		CMP	R14,#' '		;Is it a control character
		MOVLT	R14,#0			;Yes -- translate to a 0
		STRB	R14,[R0],#1		;Store in destination
		BGE	%00misc_strcpy		;No -- copy another byte
		SUB	R0,R0,#1		;Point back at terminator
		LDMFD	R13!,{R1,PC}^		;Return to caller

; --- misc__subst ---
;
; On entry:	R0 == Pointer to error message skeleton
;		R1 == Filler 1
;		R2 == Filler 2
;		R3 == Filler 3
;		R4 == Filler 4
;		R5 == Pointer to buffer
; On exit:	--

misc__subst	ROUT

		STMFD	R13!,{R1-R5,R14}	;Save some registers

00misc__subst	LDRB	R14,[R0],#1		;Get an input character
		CMP	R14,#'%'		;Is it a '%' sign?
		BEQ	%01misc__subst		;Yes -- deal with it
02misc__subst	STRB	R14,[R5],#1		;Not special, so store it
		CMP	R14,#0			;Is it the end of input?
		BNE	%00misc__subst		;No -- get another one
		LDMFD	R13!,{R1-R5,PC}^	;And return to caller

01misc__subst	LDRB	R14,[R0],#1		;Get the next character
		SUB	R1,R14,#'0'		;Get the index
		CMP	R1,#4			;Is it in range?
		BCS	%02misc__subst		;No -- just ignore the '%'
		LDR	R1,[R13,R1,LSL #2]	;Load appropriate register

03misc__subst	LDRB	R14,[R1],#1		;Get an input byte
		CMP	R14,#&20		;Is it the end of the string?
		STRCSB	R14,[R5],#1		;No -- store it in output
		BCS	%03misc__subst		;... and get another one
		B	%00misc__subst		;Yes -- read main string

		LTORG

; --- misc_error ---
;
; On entry:	R0 == Pointer to error message skeleton
;		R1 == Filler 1
;		R2 == Filler 2
;		R3 == Filler 3
;		R4 == Filler 4
; On exit:	R0 == Pointer to constructed error in misc__errorBuf

		EXPORT	misc_error
misc_error	ROUT

		STMFD	R13!,{R5,R14}
		ADR	R5,misc__errorBuf	;Point to error buffer
		LDR	R14,[R0],#4		;Read the error's number
		STR	R14,[R5],#4		;And store in the new buffer
		BL	misc__subst		;Do the substitution
		SUB	R0,R5,#4		;Point at the buffer
		LDMFD	R13!,{R5,PC}^		;And return to caller

		LTORG

; --- misc_subst ---
;
; On entry:	R0 == Pointer to error message skeleton
;		R1 == Filler 1
;		R2 == Filler 2
;		R3 == Filler 3
;		R4 == Filler 4
; On exit:	R0 == Pointer to constructed string in misc__errorBuf

		EXPORT	misc_subst
misc_subst	ROUT

		STMFD	R13!,{R5,R14}
		ADR	R5,misc__errorBuf	;Point to error buffer
		BL	misc__subst		;Do the substitution
		MOV	R0,R5			;Point at the buffer
		LDMFD	R13!,{R5,PC}^		;And return to caller

		LTORG

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

		END
