;
; pathUtil.s
;
; Messing about with path variables
;
;  1994-1998 Straylight
;

;----- Licensing note -------------------------------------------------------
;
; This file is part of Straylight's core utilities (coreutils).
;
; Coreutils 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.
;
; Coreutils 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 Coreutils.  If not, write to the Free Software Foundation,
; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

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

		GET	libs:header
		GET	libs:swis

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

		AREA	|Asm$$Code|,CODE,READONLY

; --- path_addDir ---
;
; On entry:	R0 == pointer to path variable name
;		R1 == pointer to a directory string to add in
;		R2 == flags:
;		      bits 0-7 == variable type (2 == literal, 4 == macro)
;		      bit 8    == create variable if doesn't exist
;
; On exit:	CS if path element added, CC otherwise
;		May return an error
;
; Use:		Adds a directory to the given path variable.

		EXPORT	path_addDir
path_addDir	ROUT

		BIC	R14,R14,#V_flag+C_flag	;Assume everything is great
		STMFD	R13!,{R0-R4,R14}	;Save a load of registers
		MOV	R4,R0			;Look after the variable name

		; --- Read the font path variable ---
		;
		; We must make sure we don't expand it when we do.

		BL	path__readPath		;Read the path variable
		BVS	%90path_addDir		;If it failed, return error
		MOV	R0,R1			;Point to string to find
		BL	path__findDir		;Try to find the directory
		LDMCSFD	R13!,{R0-R4,PC}^	;If it's in there, return

		; --- Add in the directory then ---

		MOV	R1,R11			;Point to the string start
		LDRB	R14,[R1,#0]		;Load the first byte
		CMP	R14,#0			;Is this a null string?
		BEQ	%20path_addDir		;Yes -- omit the comma then

		; --- Find the string end ---

10path_addDir	LDRB	R14,[R1,#1]!		;Load a new character out
		CMP	R14,#0			;Is this the end yet?
		BNE	%10path_addDir		;No -- loop round again

		MOV	R14,#','		;Store a comma over the end
		STRB	R14,[R1],#1		;Store it at the end

		; --- Copy the new directory string on the end ---

20path_addDir	LDRB	R14,[R0],#1		;Load a source string byte
		CMP	R14,#32			;Is this the string end?
		STRCSB	R14,[R1],#1		;Store it in the buffer
		BCS	%20path_addDir		;And look back round again

		; --- Now set the variable value and return ---

		AND	R2,R2,#&FF		;Get the variable type
		CMP	R2,#4			;Are we setting a lit string?
		MOVNE	R14,#0			;No -- null terminate then
		STRNEB	R14,[R1],#1		;Stick it on the end
		MOV	R0,R4			;Point to path variable name
		MOV	R4,R2			;Get variable type
		SUB	R2,R1,R11		;Get the string length out
		MOV	R1,R11			;Point to the new path string
		MOV	R3,#0			;No initial context here
		SWI	XOS_SetVarVal		;Set the variable value
		BVS	%90path_addDir		;Return an error if any

		LDMFD	R13!,{R0-R4,R14}	;Return to caller if OK
		ORRS	PC,R14,#C_flag

		; --- Deal with any errors created ---

90path_addDir	ADD	R13,R13,#4		;Don't return stacked R0
		LDMFD	R13!,{R1-R4,R14}	;Restore caller's registers
		ORRS	PC,R14,#V_flag		;Return the error

		LTORG

; --- path__readPath ---
;
; On entry:	R0 == pointer to path variable name
;		R2 == flags passed to addDir/removeDir
;
; On exit:	May return an error
;
; Use:		Reads the value of the path variable into the buffer
;		pointed to by R11.

path__readPath	ROUT

		BIC	R14,R14,#V_flag		;Clear the error indicator
		STMFD	R13!,{R0-R4,R14}	;Save a load of registers
		MOV	R1,R11			;Point to the scratch pad
		MOV	R2,#256			;Say the buffer is 256 bytes
		MOV	R3,#0			;No context space required
		MOV	R4,#0			;Don't expand the string
		SWI	XOS_ReadVarVal		;Read the variable value
		BVS	%90path__readPath	;If it failed, handle error
		MOV	R14,#0			;Store a zero byte on the end
		STRB	R14,[R1,R2]		;Terminate the path string
		LDMFD	R13!,{R0-R4,PC}^	;Return to caller now

90		LDR	R14,[R13,#8]		;Load the flags from stack
		TST	R14,#&100		;Is the `create' flag on?
		MOVNE	R14,#0			;Yes -- get a zero byte
		STRNEB	R14,[R11,#0]		;Store in buffer
		LDMNEFD	R13!,{R0-R4,PC}^	;And return to caller

		ADD	R13,R13,#4		;Don't restore R0 on exit
		LDMFD	R13!,{R1-R4,R14}	;Restore all the others
		ORRS	PC,R14,#V_flag		;Return the error to caller

		LTORG

; --- path__findDir ---
;
; On entry:	R0 == pointer to string to search for
;
; On exit:	CS and R0 == pointer into path string if successful or
;		CC and R0 preserved
;
; Use:		Tries to find a named directory within a font path string.

path__findDir	ROUT

		STMFD	R13!,{R1-R5,R14}	;Save a load of registers
		MOV	R1,R11			;Point to the path string
		MOV	R3,R1			;Keep a pointer to this dir

		; --- Go through both strings ---

00path__findDir	MOV	R2,R0			;Point to search pattern
01path__findDir	LDRB	R4,[R1],#1		;Load a char from the path
		CMP	R4,#32			;Is it a space character?
		BEQ	%01path__findDir	;Yes -- ignore it then

02path__findDir	LDRB	R5,[R2],#1		;And one from the pattern
		CMP	R5,#32			;Is this the end of the dir?
		BCC	%10path__findDir	;Yes -- deal with this

		CMP	R4,#0			;Is it the end of the path?
		BEQ	%07path__findDir	;Yes -- deal with this

		CMP	R4,R5			;Do the characters match?
		LDREQB	R4,[R1],#1		;Yes -- load next path char
		BEQ	%02path__findDir	;And go round again

		; --- Found a mismatch ---
		;
		; We have to find the next path element

05path__findDir	CMP	R4,#','			;Is it a comma?
		SUBEQ	R3,R1,#1		;Yes -- point to it nicely
		BEQ	%00path__findDir	;And go round again
		CMP	R4,#0			;Is it the string end?
		LDRNEB	R4,[R1],#1		;Load a char from the path
		BNE	%05path__findDir	;No -- continue the search
07path__findDir	LDMFD	R13!,{R1-R5,R14}	;Restore the registers
		BICS	PC,R14,#C_flag		;Return with carry clear

		; --- We reached the end of the directory ---

10path__findDir	CMP	R4,#32			;Is it a space?
		LDREQB	R4,[R1],#1		;Load a char from the path
		BEQ	%10path__findDir	;Yes -- allow trailing space
		CMP	R4,#','			;Is it a comma?
		CMPNE	R4,#0			;Or the end of the whole lot?
		BNE	%05path__findDir	;No -- find the next one
		MOV	R0,R3			;Point to the path entry strt
		LDMFD	R13!,{R1-R5,R14}	;Restore the registers
		ORRS	PC,R14,#C_flag		;And return a success

		LTORG

; --- path_removeDir ---
;
; On entry:	R0 == pointer to name of path variable
;		R1 == pointer to a directory to remove
;		R2 == flags:
;		      bits 0-7 == variable type (2 == literal, 4 == macro)
;		      bit 8    == create variable if doesn't exist
;
; On exit:	May return an error
;
; Use:		Removes an element from a given path variable.

		EXPORT	path_removeDir
path_removeDir	ROUT

		BIC	R14,R14,#V_flag+C_flag	;Clear error indicator
		STMFD	R13!,{R0-R4,R14}	;Save a load of registers
		MOV	R4,R0			;Look after variable name

		BL	path__readPath		;Read the actual path string
		BVS	%90path_removeDir	;If it failed, handle it
		MOV	R0,R1			;Point to path element
		BL	path__findDir		;Find the particular entry
		LDMCCFD	R13!,{R0-R4,PC}^	;Not there -- return

		; --- Now find the end of the entry ---

		ADD	R1,R0,#1		;Keep the start pointer
10		LDRB	R14,[R1],#1		;Load a byte from it
		CMP	R14,#','		;Is it the dir end?
		CMPNE	R14,#0			;Or the end of the whole lot?
		BNE	%10path_removeDir	;No -- go round again then

		; --- Now remove this item from the list ---

		CMP	R14,#','		;Is this character a comma?
		CMPEQ	R0,R11			;And is the dir at the start?
		STRNEB	R14,[R0],#1		;Neither -- store it here

20		CMP	R14,#0			;Is this the string end?
		BEQ	%50path_removeDir	;Yes -- go and set the var
		LDRB	R14,[R1],#1		;Get a new char from the path
		STRB	R14,[R0],#1		;And store it nicely
		B	%20path_removeDir	;And go round for more

		; --- Right -- the string bashing's over ---

50		AND	R1,R2,#&FF		;Get the variable type
		CMP	R1,#4			;Are we setting a lit string?
		SUBEQ	R0,R0,#1		;Yes -- don't include null

		SUB	R2,R0,R11		;Get the length in R2 nicely
		MOV	R0,R4			;Point to the variable name
		MOV	R4,R1			;Get the variable type
		MOV	R1,R11			;Point to the string start
		MOV	R3,#0			;Don't mess with wildcards
		SWI	XOS_SetVarVal		;Set the variable value
		BVS	%90path_removeDir	;If it failed, return error

		LDMFD	R13!,{R0-R4,R14}	;Return to caller
		ORRS	PC,R14,#C_flag

		; --- Something went wrong ---

90		ADD	R13,R13,#4		;Don't restore R0 on exit
		LDMFD	R13!,{R1-R4,R14}	;Restore all the others
		ORRS	PC,R14,#V_flag		;And return the error

		LTORG

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

		END
