;
; currDir.s
;
; Puts the current directory in a code variable
;
;  1994-1998 Straylight
;

;----- Licensing note -------------------------------------------------------
;
; CurrDir 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.
;
; CurrDir 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 CurrDir.  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

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

		IMPORT	version
		IMPORT	|Image$$RW$$Limit|

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

		AREA	|Asm$$Code|,CODE,READONLY
		ENTRY

; --- main ---
;
; On entry:	--
;
; On exit:	Via OS_Exit
;
; Use:		Installs the CurrDir variable.

main		ROUT

		; --- Check for RISC OS 3 ---

		MOV	R0,#129			;Read OS version number
		MOV	R1,#0
		MOV	R2,#255
		SWI 	OS_Byte
		CMP	R1,#&A3			;Check for RISC OS 3
		BLO	cd__badOSVer		;Wrong -- make an error

		; --- Parse the command line arguments ---

		ADRL	R12,|Image$$RW$$Limit|	;Find the program end
		SWI	OS_GetEnv		;Read the command line
cd__skipLoop	LDRB	R14,[R0],#1		;Get next byte from this
		CMP	R14,#32			;Is it the end of the name?
		BHI	cd__skipLoop		;No -- go round again
cd__spaceLoop	CMP	R14,#32			;Is this a space?
		LDREQB	R14,[R0],#1		;Yes -- get another byte
		BEQ	cd__spaceLoop		;And go round again
		SUB	R1,R0,#1		;Point at nonspace char
		ADR	R0,cd__cliDef		;Point to the command defn
		MOV	R2,R12			;Point to my output buffer
		MOV	R3,#256			;And get its size
		SWI	OS_ReadArgs		;Read the arguments nicely

		; --- Check for help ---

		LDR	R14,[R12,#8]		;Load the help flag
		CMP	R14,#0			;Is it set?
		BNE	cd__help		;Yes -- then give help

		; --- Now find the variable name ---

		LDR	R4,[R12,#0]		;Load the name value
		CMP	R4,#0			;Is it set?
		ADREQ	R4,cd__defaultName	;No -- point to a default

		; --- Do the right thing ---

		LDR	R14,[R12,#12]		;Load the `remove' flag
		CMP	R14,#0			;Is it set?
		BNE	cd__remove		;Yes -- remove the variable

		; --- Load the maximum length of the string ---

		LDR	R1,[R12,#4]		;Load the length value
		CMP	R1,#0			;Is it zero?
		MOVEQ	R2,#-1			;Yes -- have a very big max
		BEQ	cd__gotLength		;And skip onwards
		MOV	R0,#10+(1<<31)		;Default is base 10
		SWI	OS_ReadUnsigned		;Read the value nicely
		CMP	R2,#20			;Is the length OK?
		BLO	cd__badLength		;No -- that's an error
cd__gotLength	STR	R2,cd__maxLen		;Store the length in code

		; --- Set the variable value ---

		MOV	R0,R4			;Point to the variable name
		ADR	R14,cd__varBase		;Point to the variable base
		LDMIA	R14,{R1,R2}		;Load the base and length
		MOV	R3,#0			;No context value
		MOV	R4,#16			;This is a code variable
		SWI	OS_SetVarVal		;Install the variable nicely
		SWI	OS_Exit

		; --- Remove an installed variable ---

cd__remove	MOV	R0,R4			;Point to the variable name
		MOV	R2,#-1			;Remove the variable
		MOV	R3,#0			;No context value
		MOV	R4,#16			;Remove code variable
		SWI	OS_SetVarVal		;Remove the variable
		SWI	OS_Exit

cd__cliDef	DCB	"var,maxlen=length,help/S,remove/S",0
cd__defaultName	DCB	"CSD",0

cd__badOSVer	ADR	R0,cd__ro3Only		;Point to the error message
		SWI	OS_GenerateError	;Report the error

cd__ro3Only	DCD	1
		DCB	"currDir only works on RISC OS 3.00 or later",0

cd__badLength	ADR	R0,cd__minSize		;Point to the error message
		SWI	OS_GenerateError	;Report the error

cd__minSize	DCD	1
		DCB	"Maximum length must be at least 20",0

cd__varBase	DCD	cd__variable
		DCD	cd__varEnd-cd__variable+512

		; --- Return help on the program ---

cd__help	ADR	R0,cd__helpText		;Point to the help text
		MOV	R1,#0			;Use the default dictionary
		ADR	R2,version		;Point to the version string
		SWI	OS_PrettyPrint		;Print the string
		SWI	OS_Exit

cd__helpText	DCB	27,0,13
		DCB	13
		DCB	"Syntax: currDir [-var <variableName>] "
		DCB	"[-maxlen <length>] [-remove]",13
		DCB	13
		DCB	"Sets a variable (by default the variable 'CSD', "
		DCB	"although you can change this) to contain the name "
		DCB	"of the currently selected directory.",13
		DCB	13
		DCB	"Optionally, you can set a maximum length.  If you "
		DCB	"do, the directory name will be shortened to only "
		DCB	"display the name of the filing system, disk name "
		DCB	"(if present), and the tail end of the path.",13
		DCB	0

;----- The code variable ----------------------------------------------------

cd__variable	ROUT

		B	 cd__cantWrite		;Handle attempt to write

		; --- Perform the read operation ---

		STMFD	R13!,{R3-R5,R12,R14}	;Save some registers
		ADR	R12,cd__buffer		;Set up the buffer pointer
		MOV	R0,#37			;Canonicalise path
		ADR	R1,cd__atSign		;Point to the `@' magic char
		MOV	R2,R12			;Point at the buffer
		MOV	R3,#0			;No path variable
		MOV	R4,#0			;No path variable still
		MOV	R5,#512			;The size of my buffer
		SWI	XOS_FSControl		;Read the canonical path
		ADRVS	R2,cd__unset		;If not point at default

		; --- Count the length ---

		MOV	R0,R12			;Point at the buffer
		MOV	R1,R12			;Start truncate at beginning
		MOV	R2,#0			;Current length
		MOV	R3,#0			;Current state

00cd__variable	LDRB	R14,[R0],#1		;Load the next byte
		CMP	R14,#32			;Is this the string end?
		BLO	%10cd__variable		;Yes -- skip to the end
		ADD	R2,R2,#1		;Bump the length counter
		CMP	R14,#':'		;Is it a colon?
		BEQ	%02cd__variable		;Yes -- handle it then
		CMP	R14,#'%'		;Is it a library?
		CMPNE	R14,#'$'		;Or a root spec?
		CMPNE	R14,#'&'		;Or a URD spec?
		MOVEQ	R1,R0			;Yes -- truncate here
		CMP	R14,#'.'		;Is it a dot?
		BNE	%00cd__variable		;No -- go round again

		; --- We found a dot ---

		CMP	R3,#2			;Did we find two colons?
		SUBEQ	R1,R0,#1		;Yes -- truncate here
		MOVEQ	R3,#3			;And don't do it again
		B	%00cd__variable		;Go round again

		; --- Found a colon -- check it out ---

02cd__variable	CMP	R3,#0			;How many colons matched?
		MOVEQ	R1,R0			;None yet -- truncate here
		CMPNE	R3,#1			;Or maybe we've had one
		ADDEQ	R3,R3,#1		;Bump the counter
		B	%00cd__variable		;Go round again

		; --- Check the length now ---

10cd__variable	LDR	R5,cd__maxLen		;Load the maximum length
		SUBS	R4,R2,R5		;Are we OK here?
		BLS	%30cd__variable		;Yes -- skip onwards then

		; --- Truncate the string ---
		;
		; R4 is how many bytes we have to lose.

		ADD	R0,R1,R4		;Point to where we copy from
		MOV	R2,#3			;Countdown for ellipsis
20cd__variable	LDRB	R14,[R0],#1		;Load the byte out
		CMP	R14,#32			;Is this the end of it all?
		BLO	%25cd__variable		;Yes -- skip to end then
		SUBS	R2,R2,#1		;No -- decrement countdown
		MOVGE	R14,#'.'		;Substitute a dot if needed
		STRB	R14,[R1],#1		;Store the byte in buffer
		B	%20cd__variable		;No -- go round again then

25cd__variable	STRB	R14,[R1],#1		;Store the byte in buffer
		MOV	R2,R5			;Length is in R2 on exit

		; --- Return the variable ---

30cd__variable	MOV	R0,R12			;Point to the string
		LDMFD	R13!,{R3-R5,R12,PC}^	;Return to caller

cd__maxLen	DCD	0
cd__atSign	DCB	"@",0
cd__unset	DCB	"<Unset>",0

		; --- Make an error about writing to the variable ---

cd__cantWrite	ADR	R0,cd__writeMsg		;Point to error
		ORRS	PC,R14,#V_flag		;And return it

cd__writeMsg	DCD	1
		DCB	"Can't write current directory variables",0

		ALIGN

cd__buffer

cd__varEnd

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

		END
