;
; fontMenu.s
;
; Fontmenu creation
;
;  1994-1998 Straylight
;

;----- Licensing note -------------------------------------------------------
;
; This file is part of Straylight's Sapphire library.
;
; Sapphire 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.
;
; Sapphire 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 Sapphire.  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

		GET	libs:stream

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

		GET	sapphire:alloc
		GET	sapphire:event
		GET	sapphire:flex
		GET	sapphire:menu
		GET	sapphire:menuDefs
		GET	sapphire:msgs
		GET	sapphire:sapphire
		GET	sapphire:string

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

		AREA	|Sapphire$$Code|,CODE,READONLY

; --- fm_create ---
;
; On entry:	R0 == current font name
;		R1 == handler to call when selection made
;		R2 == R10 value to call with
;		R3 == R12 value to call with
;		R4 == pointer to routine to call to create submenu
;		      (ie. menu_create or tms_create)
;
; On exit:	CS if any fonts exist and
;                 R0 == pointer to a menu definition
;		  R1 == event handler to call
;		  R2 == R10 value for event handler
;		  R3 == R12 value for event handler
;		else CC and
;		  R0-R3 corrupted
;		May return an error
;
; Use:		Creates a user menu definition suitable for passing directly
;		to (menu|tms)_create. Note however, that the menu defintion
;		does *not* include any title; this must be created first.
;		If you require items such as the system font, then
;		add these to the menu before creating the menu returned
;		from this call.

		EXPORT	fm_create
fm_create	ROUT

		STMFD	R13!,{R0,R4-R10,R12,R14} ;Save some registers
		WSPACE	fm__wSpace

		; --- Save the caller's handler ---

		ADR	R14,fm__userHandler	;Point to the handler
		STMIA	R14,{R1-R4}		;Store it away

		; --- Ensure that we need to create it ---

		MOV	R0,R11			;Build path in scratchpad
		BL	fm__fontPath		;Get the current fontpath
		BCC	%70fm_create		;None found -- no fonts then

		LDR	R14,fm__flags		;Load the flags word
		TST	R14,#fmFlag__changed	;Have the fonts changed?
		BICNE	R14,R14,#fmFlag__changed ;Yes -- clear the flag
		STRNE	R14,fm__flags		;...store the flags
		BNE	%00fm_create		;...and recreate the menu

		LDR	R1,fm__block		;Load our block address
		MOVS	R2,R1			;Is it defined yet?
		ADRNE	R1,fm__path		;Point to saved font path
		BLNE	str_cmp			;Compare with current path
		MOVNE	R2,#0			;If not equal, clear pointer
		CMP	R2,#0			;So, do we recreate?
		BNE	%40fm_create		;No -- return current menu

		MOV	R1,R11			;Point to font path string
		ADR	R0,fm__path		;Point to font path buffer
		BL	str_cpy			;Take a copy of the path

00fm_create	LDR	R0,fm__block		;Load address of menu block
		CMP	R0,#0			;Is it created currently?
		BLNE	free			;Yes -- free it then

		; --- Set up a flex block ---
		;
		; We will read the font names into this block, to make it
		; easier to actually build our menu, and reduce heap
		; fragmentation.
		;
		; The format of the data in the block is as follows:
		;
		;	 Size	Use
		;     /	  4	Number of variants (0 for regular only)
		;     |	  ?	Name of this family
		;     \	[ ?	Name of this variant

		SUB	R13,R13,#12		;Make a small anchor block
		MOV	R0,R13			;Point to the block
		MOV	R1,#1024		;Start it off at 256 bytes
		BL	flex_alloc		;Allocate the block
		BLCS	alloc_error		;If it failed, get error
		BCS	%80fm_create		;And return to caller

		MOV	R0,#0			;Start at the beginning
		STMIB	R13,{R0,R1}		;Save them in the block

		MOV	R9,#4			;No length for main menu
		MOV	R10,#0			;Or for the submenus

		; --- Start building font names now ---

		MOV	R2,#0			;Start from the beginning
		MOV	R1,R11			;Build string in ScratchPad
		MOV	R3,#256			;Size of scratchpad buffer
		SWI	Font_ListFonts		;Read a font name
		CMP	R2,#-1			;Is that the very end?
		BEQ	%65fm_create		;Yes -- abort now then
		MOV	R4,#0			;Found one family so far

		MOV	R6,#0			;Clear a flags word
		MOV	R1,R11			;Point to the font name
		BL	fm__parse		;Break the name up
		ORRCC	R6,R6,#1		;If `Regular', set a flag
		MOV	R3,R1			;Look after variant name
		MOV	R8,R0			;Look after the family name

		; --- Set this family name up ---

10fm_create	MOV	R5,#0			;This is the first variant

		MOV	R0,R13			;Point to the anchor block
		MOV	R1,#4			;Make space for count word
		BL	fm__ensure		;Allocate space for it
		BVS	%79fm_create		;If we couldn't, abort
		ADD	R7,R0,#4		;Point just past this word

		FSAVE	R7			;Save R7 on relocation stack
		MOV	R1,R8			;Get family name in R1
		MOV	R0,R13			;Point to the anchor block
		BL	fm__string		;Write the family name out
		BVS	%79fm_create		;If it failed, abort now
		ADD	R0,R0,#3+8		;Word align returned length
		BIC	R0,R0,#3		;Tumtetiddlytumtetum
		ADD	R9,R9,R0		;Add on to main menu length
		ADD	R9,R9,#4		;Remember space for radio
		ADD	R10,R10,R0		;And add on submenu length

		; --- Write this variant out ---

15fm_create	MOV	R0,R13			;Point to anchor block
		MOV	R1,R3			;Point to variant name
		BL	fm__string		;Add this on the end
		BVS	%79fm_create		;If it failed, abort now
		ADD	R0,R0,#3+12		;Word align returned length
		BIC	R0,R0,#3		;Omtiddlyompepom
		ADD	R10,R10,R0		;Add this to submenu length
		ADD	R5,R5,#1		;Increment variant counter

		; --- Get the next font name ready ---

		MOV	R8,R6			;Remember current flags
		MOV	R1,R11			;Build string in ScratchPad
		MOV	R3,#256			;Size of scratchpad buffer
		SWI	Font_ListFonts		;Read a font name
		CMP	R2,#-1			;Is that the very end?
		BEQ	%20fm_create		;Yes -- we've finished then

		BL	fm__parse		;Break up the font name
		ORRCC	R6,R6,#1		;If `Regular', set a flag
		BICCS	R6,R6,#1		;Otherwise clear it

		MOV	R3,R1			;Look after the variant name
		FLOAD	R1			;Restore family name address
		BL	str_cmp			;Do the strings match?
		FSAVE	R1			;Save the address back
		BEQ	%15fm_create		;And loop round for more

		; --- Finished a family ---

20fm_create
		FLOAD	R7			;Reload family name address
		CMP	R5,R8			;Is there only `Regular'?
		MOVEQ	R5,#0			;Yes -- claim no variants
		STR	R5,[R7,#-4]		;Save it in the block
		MOV	R8,R0			;Look after the family name
		MOV	R0,R13			;Point to anchor block
		BL	fm__align		;Word align output pointer
		ADD	R4,R4,#1		;Increment family counter
		CMP	R2,#-1			;Are there more font names?
		BNE	%10fm_create		;Yes -- put them in the block

		; --- Allocate a big heap block ---

		ADD	R0,R9,R10		;Add the menu sizes up
		ADD	R0,R0,R4,LSL #2		;And an indexing block
		BL	alloc			;Allocate this block
		BLCS	alloc_error		;If it failed, get error
		BCS	%79fm_create		;And return to caller

		STR	R0,fm__block		;Store this block address

		; --- A note about register allocation ---
		;
		; Dear reader,
		;   I have decided, it being Saturday and all, to allocate
		; registers thusly:
		;
		;  R7 == pointer into submenu indexing table
		;  R8 == pointer into the main menu structure
		;  R9 == pointer into the submenu area
		; R10 == pointer into our juicy big flex table
		;
		; 		Yours sincerely
		;
		;			Mark Wooding (Straylight Dev Lab)

		MOV	R7,R0			;Point to indexing table
		ADD	R8,R7,R4,LSL #2		;Find the main menu area
		ADD	R9,R8,R9		;And find the submenu area
		LDR	R10,[R13,#0]		;Load base of flex block
		STR	R8,fm__menu		;Store the menu address

		; --- Now the fun begins ---

22fm_create	MOV	R0,#mFlag_radio		;Get the flag ready
		ORR	R0,R0,#mFlag_R12	;And make data R12-relative
		LDR	R6,[R10],#4		;Load the number of variants
		CMP	R6,#0			;Do we want a submenu?
		ORRNE	R0,R0,#mFlag_subWarn	;Yes -- set the flag then
		STR	R0,[R8],#4		;Save it in the menu block

		MOVEQ	R14,#0			;No submenu -- get null ptr
		STREQ	R14,[R7],#4		;And clear submenu address
		STRNE	R9,[R7],#4		;Save this submenu address

		MOV	R0,R10			;Look after this address
23fm_create	LDRB	R14,[R10],#1		;Load a family name byte
		CMP	R14,#0			;Is this the end yet?
		STRB	R14,[R8],#1		;Save it in the menu block
		BNE	%23fm_create		;And go round for the rest

		ADD	R8,R8,#3		;Word align the output addr
		BIC	R8,R8,#3		;Yingtongiddleipo

		MOV	R1,#4			;Offset 0 in radio block
		MOV	R2,R8			;Magic radio group tag
		STMIA	R8!,{R1,R2}		;Save these in the block

		; --- Now build the variants submenu ---

		CMP	R6,#0			;Do we want a submenu
		BEQ	%28fm_create		;No -- *still skip past name*

		MOV	R14,#0			;Title flags
		STR	R14,[R9],#4		;Save in submenu block
24fm_create	LDRB	R14,[R0],#1		;Load a family name byte
		STRB	R14,[R9],#1		;Save it in the menu block
		CMP	R14,#0			;Is this the end yet?
		BNE	%24fm_create		;And go round for the rest

		ADD	R9,R9,#3		;Word align the output addr
		BIC	R9,R9,#3		;Obblyjobblywibbledidee

		; --- Create an item for each variant ---

25fm_create	MOV	R0,#mFlag_radio		;Get the flag ready
		ORR	R0,R0,#mFlag_R12	;And make data R12-relative
		STR	R0,[R9],#4		;Save in submenu block

26fm_create	LDRB	R14,[R10],#1		;Load a variant name byte
		CMP	R14,#0			;Is this the end yet?
		STRB	R14,[R9],#1		;Save it in the menu block
		BNE	%26fm_create		;And go round for the rest

		ADD	R9,R9,#3		;Word align the output addr
		BIC	R9,R9,#3		;Obblyjobblywibbledidee

		MOV	R1,#8			;Offset 8 in radio block
		MOV	R2,R9			;Magic radio group tag
		STMIA	R9!,{R1,R2}		;Save these in the block

		SUBS	R6,R6,#1		;Decrement the counter
		BGT	%25fm_create		;And do the rest of them

		MOV	R14,#mFlag_end		;Terminate the menu
		STR	R14,[R9],#4		;Save that at the end

		B	%30fm_create		;Skip to end of family stuff

		; --- No variants -- omit the submenu ---
		;
		; For odd reasons, we actually leave a `(Regular)' item
		; in the flex block.  We need to skip over this here.

28fm_create	LDRB	R14,[R10],#1		;Load a variant name byte
		CMP	R14,#0			;Is this the end yet?
		BNE	%28fm_create		;And go round for the rest

30fm_create	ADD	R10,R10,#3		;Word align flex block ptr
		BIC	R10,R10,#3		;[Silly comment omitted]

		SUBS	R4,R4,#1		;Done another family
		BGT	%22fm_create		;And go round for the rest

		MOV	R14,#mFlag_end		;Terminate the menu
		STR	R14,[R8],#4		;Save that at the end

		; --- Destroy the flex block ---

		MOV	R0,R13			;Point to the flex anchor
		BL	flex_free		;Free the block
		ADD	R13,R13,#12		;Restore stack pointer

		; --- Now return the menu and things ---

40fm_create	LDR	R0,[R13],#4		;Load the name to tick
		BL	fm_tickFont		;Tick that font
		LDR	R0,fm__menu		;Find the menu address
		ADR	R1,fm__handler1		;I don't have a handler :-(
		MOV	R2,#0			;No R10 value either :~-(
		MOV	R3,R12			;And pass workspace in R12
		LDMFD	R13!,{R4-R10,R12,R14}	;Restore registers
		ORR	R14,R14,#C_flag		;Set C to say we did it
		BICS	PC,R14,#V_flag		;And return errorless

		; --- Couldn't find any fonts (oops) ---

65fm_create	ADD	R13,R13,#12		;Restore stack pointer
70fm_create	LDMFD	R13!,{R0,R4-R10,R12,R14} ;Restore registers
		BICS	PC,R14,#V_flag+C_flag	;And return CC

		; --- Tidy up after catastrophes ---

79fm_create	MOV	R10,R0			;Look after the error
		MOV	R0,R13			;Point to the flex anchor
		BL	flex_free		;Free the flex block
		MOV	R0,R10			;Restore the error pointer

80fm_create	ADD	R13,R13,#12+4		;Restore the stack nicely
		LDMFD	R13!,{R4-R10,R12,R14}	;Restore registers
		ORRS	PC,R14,#V_flag		;And return the error

		LTORG

; --- fm__handler1 ---
;
; On entry:	R0 == menu event
;		R1 == menu item
;		R12 == pointer to private workspace
;
; On exit:	--
;
; Use:		Handles events on the first level menu.

fm__handler1	ROUT

		CMP	R0,#mEvent_select	;Is it a menu selection
		CMPNE	R0,#mEvent_subMenu	;Or a submenu event?
		MOVNES	PC,R14			;Nope -- return

		STMFD	R13!,{R1-R4,R14}	;Stack registers
		CMP	R0,#mEvent_select	;A selection?
		BEQ	%50fm__handler1		;Yes -- jump ahead

		; --- Handle submenu events ---

		LDR	R0,fm__block		;Point to useful table
		LDR	R0,[R0,R1,LSL #2]	;Load submenu address
		MOV	R2,R1			;Pass item number in R10
		ADR	R1,fm__handler2		;And point to second handler
		MOV	R3,R12			;And workspace in R12
		LDR	R4,fm__creator		;Load address of creator
		MOV	R14,PC			;Set up return address
		MOV	PC,R4			;Call the creator
		B	%90fm__handler1		;Return to caller

		; --- User selected an item ---

50fm__handler1	MOV	R3,R1			;Remember index value
		BL	fm__familyName		;Get family name pointer
		MOV	R1,R0			;Put it in R1
		ADR	R0,fm__name		;Write the name here
		BL	str_cpy			;Copy over family name
		MOV	R2,R0			;Put terminator ptr in R2
		LDR	R0,fm__block		;Load table pointer
		LDR	R0,[R0,R3,LSL #2]	;Load submenu pointer
		CMP	R0,#0			;Is there a submenu?
		BEQ	%60fm__handler1		;No -- jump ahead
		MOV	R1,#0			;Just choose first index
		BL	fm__variantName		;Find the first variant name
		CMP	R0,#0			;Is there one?
		BEQ	%60fm__handler1		;No -- return now then
		MOV	R1,R0			;Put it in R1
		MOV	R0,R2			;Copy it to here
		MOV	R14,#'.'		;We want a '.' first
		STRB	R14,[R0],#1		;Store in the string
		BL	str_cpy			;Copy over the string

60fm__handler1	MOV	R0,#fmEvent_select	;The event type
		ADR	R1,fm__name		;Point to the name
		BL	fm__dispatch		;Dispatch the event

90fm__handler1	LDMFD	R13!,{R1-R4,PC}^	;Load back registers

		LTORG

; --- fm__handler2 ---
;
; On entry:	R0 == menu event
;		R1 == menu item
;		R10 == menu item submenu came from
;		R12 == pointer to workspace
;
; On exit:	--
;
; Use:		Handles events for a second level submenu

fm__handler2	ROUT

		CMP	R0,#mEvent_select	;Is it a menu selection
		MOVNES	PC,R14			;Nope -- return

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

		MOV	R3,R1			;Remember index value
		MOV	R1,R10			;Get previous index
		BL	fm__familyName		;Get family name pointer
		MOV	R1,R0			;Put it in R1
		ADR	R0,fm__name		;Write the name here
		BL	str_cpy			;Copy over family name
		MOV	R2,R0			;Put terminator ptr in R2
		LDR	R0,fm__block		;Load table pointer
		LDR	R0,[R0,R10,LSL #2]	;Load submenu pointer
		MOV	R1,R3			;Put index in R1
		BL	fm__variantName		;Find the variant name
		CMP	R0,#0			;Is there a name?
		BEQ	%10fm__handler2		;No -- retur now then
		MOV	R1,R0			;Put it in R1
		MOV	R0,R2			;Copy it to here
		MOV	R14,#'.'		;We want a '.' first
		STRB	R14,[R0],#1		;Store in the string
		BL	str_cpy			;Copy over the string

10fm__handler2	MOV	R0,#fmEvent_select	;The event type
		ADR	R1,fm__name		;Point to the name
		BL	fm__dispatch		;Dispatch the event

		LDMFD	R13!,{R1-R3,PC}^	;Load back registers

		LTORG

; --- fm__dispatch ---
;
; On entry:	R0-R9 == event data
;		R12 == workspace pointer
;
; On exit:	--
;
; Use:		Sends an event to the users font menu handler.

fm__dispatch	ROUT

		STMFD	R13!,{R9,R10,R12,R14}	;Stack registers
		ADR	R14,fm__userHandler	;Point to the handler
		LDMIA	R14,{R9,R10,R12}	;Load registers
		CMP	R9,#0			;Sanity check
		MOV	R14,PC			;Sey up return address
		MOVNE	PC,R9			;Call the handler
		LDMFD	R13!,{R9,R10,R12,PC}^	;Return to caller

		LTORG

; --- fm_tickFont ---
;
; On entry:	R0 == name to tick
;
; On exit:	--
;
; Use:		Ticks the font with tht given name in the fontmenu. If
;		no font exists then the existing ticks are removed

		EXPORT	fm_tickFont
fm_tickFont	ROUT

		CMP	R0,#0			;Is R0 NULL?
		MOVEQS	PC,R14			;Yes -- return now
		STMFD	R13!,{R0-R4,R14}	;Stack some registers
		WSPACE	fm__wSpace		;Locate my workspace
		MOV	R1,R0			;Put the name in R1
		MOV	R0,R11			;Point to the scratchpad
		BL	str_cpy			;Copy the string over
		MOV	R1,R11			;Put the pointer in R1
		BL	fm__parse		;Parse up the string
		MOVCS	R4,#1			;Not regular
		MOVCC	R4,#0			;Yes it is sir
		MOV	R3,R1			;Put variant name in R3

		; --- Clear the existing ticks ---

		MOV	R14,#0			;Get a NULL word
		STR	R14,fm__ticks		;Clear first tick
		STR	R14,fm__ticks+4		;And second tick

		; --- Search for the font name ---

		LDR	R1,fm__menu		;Point to the menu definition
		MOV	R2,#0			;Index so far
00fm_tickFont	LDR	R14,[R1],#4		;Load the flags word
		TST	R14,#mFlag_end		;Have we reached the end?
		BNE	%90fm_tickFont		;Yes -- return
		BL	str_icmp		;Does this name match
		BEQ	%50fm_tickFont		;Yes -- jump ahead
10fm_tickFont	LDRB	R14,[R1],#1		;Load a character
		CMP	R14,#0			;Is it a terminator?
		BNE	%10fm_tickFont		;No -- keep on looking
		ADD	R1,R1,#3+8		;Word align, skip over data
		BIC	R1,R1,#3
		ADD	R2,R2,#1		;Increment the index
		B	%00fm_tickFont		;Keep on looking

		; --- We have found a match ---
		;
		; First we must get the tick word thing

50fm_tickFont	LDRB	R14,[R1],#1		;Load a character
		CMP	R14,#0			;Is it a terminator?
		BNE	%50fm_tickFont		;No -- keep on looking
		ADD	R1,R1,#3+4		;Word align, pount to thing
		BIC	R1,R1,#3
		LDR	R14,[R1]		;Load the data word thing
		STR	R14,fm__ticks		;Store as first level tick

		; --- Now search the submenu ---

		LDR	R1,fm__block		;Point to table
		LDR	R1,[R1,R2,LSL #2]	;Load submenu pointer
		CMP	R1,#0			;Is there one?
		BEQ	%90fm_tickFont		;Nope -- return

		MOV	R0,R3			;Put variant name in R0

		; --- Skip over title data ---

		ADD	R1,R1,#4		;Skip over flags word
52fm_tickFont	LDRB	R14,[R1],#1		;Load a byte
		CMP	R14,#0			;Have we reach the end?
		BNE	%52fm_tickFont		;No -- keep looking
		ADD	R1,R1,#3		;Word align
		BIC	R1,R1,#3

                ; --- Select 'Regular' if appropriate ---

                CMP	R4,#0			;Did user select 'Regular'?
                ADDEQ	R1,R1,#4		;Yes -- skip over glags
                BEQ	%58fm_tickFont		;...and tick this one then

		; --- Now search for the family name ---

54fm_tickFont	LDR	R14,[R1],#4		;Load the flags word
		TST	R14,#mFlag_end		;Have we reached the end?
		BNE	%90fm_tickFont		;Yes -- return
		BL	str_icmp		;Does this name match
		BEQ	%58fm_tickFont		;Yes -- jump ahead
56fm_tickFont	LDRB	R14,[R1],#1		;Load a character
		CMP	R14,#0			;Is it a terminator?
		BNE	%56fm_tickFont		;No -- keep on looking
		ADD	R1,R1,#3+8		;Word align, skip over data
		BIC	R1,R1,#3
		B	%54fm_tickFont		;Keep on looking

		; --- We have found a match ---

58fm_tickFont	LDRB	R14,[R1],#1		;Load a character
		CMP	R14,#0			;Is it a terminator?
		BNE	%58fm_tickFont		;No -- keep on looking
		ADD	R1,R1,#3+4		;Word align, pount to thing
		BIC	R1,R1,#3
		LDR	R14,[R1]		;Load the data word thing
		STR	R14,fm__ticks+4		;Store as first level tick

		; --- Return to caller ---

90fm_tickFont	LDMFD	R13!,{R0-R4,PC}^	;Return to caller

		LTORG

; --- fm__familyName ---
;
; On entry:	R1 == index of name
;		R12 == workspace pointer
;
; On exit:	R0 == poiner to family name
;
; Use:		Points to the family name for the given menu index

fm__familyName	ROUT

		STMFD	R13!,{R1,R14}		;Stack registers
		LDR	R0,fm__menu		;Point to the menu block

		ADD	R0,R0,#4		;Skip over flags word
		CMP	R1,#0			;Is this index 0?
		BEQ	%90fm__familyName	;Yes -- return happy then
00		LDRB	R14,[R0],#1		;Load a byte
		CMP	R14,#0			;Is it the end?
		BNE	%00fm__familyName	;No -- keep looking
		ADD	R0,R0,#3+8+4		;Word align and point to next
		BIC	R0,R0,#3
		SUBS	R1,R1,#1		;Decrement the count
		BNE	%00fm__familyName	;And keep on looking

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

		LTORG

; --- fm__variantName ---
;
; On entry:	R0 == pointer to submenu
;		R1 == index of name
;		R12 == workspace pointer
;
; On exit:	R0 == poiner to family name, or 0 for regular
;
; Use:		Points to the family name for the given menu index

fm__variantName	ROUT

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

		ADD	R0,R0,#4		;Skip over flags word

00		LDRB	R14,[R0],#1		;Load a byte
		CMP	R14,#0			;Is it the end?
		BNE	%00fm__variantName	;No -- keep looking
		ADD	R0,R0,#3+4		;Word align and point to fst
		BIC	R0,R0,#3

		CMP	R1,#0			;Is this index 0?
		BEQ	%90fm__variantName	;Yes -- return happy then
10		LDRB	R14,[R0],#1		;Load a byte
		CMP	R14,#0			;Is it the end?
		BNE	%10fm__variantName	;No -- keep looking
		ADD	R0,R0,#3+8+4		;Word align and point to next
		BIC	R0,R0,#3
		SUBS	R1,R1,#1		;Decrement the count
		BNE	%10fm__variantName	;And keep on looking

90		MOV	R1,R0			;Put string in R1
		ADR	R0,fm__regular		;Point to regular name
		BL	msgs_lookup 		;Translate it
		BL	str_cmp			;Is this a match?
		MOVNE	R0,R1			;No -- return name then
		MOVEQ	R0,#0			;Yes -- return 0 then
		LDMFD	R13!,{R1,PC}^		;Return to caller

		LTORG

; --- fm__parse ---
;
; On entry:	R1 == pointer to font name
;
; On exit:	R0 == pointer to font family name (R1 on entry)
;		R1 == pointer to font variant name
;		CS if variant spcified explicitly, CC if `Regular'
;
; Use:		Parses a font name into a family and variant.

fm__parse	ROUT

		STMFD	R13!,{R2,R3,R14}	;Save some registers
		MOV	R2,R1			;Look after start pointer

00fm__parse	LDRB	R14,[R1],#1		;Load next byte from name
		CMP	R14,#'.'		;Is this a dot?
		BEQ	%10fm__parse		;Yes -- found the variant
		CMP	R14,#32			;Is this the end?
		BCS	%00fm__parse		;No -- keep looking then

		; --- Reached end of name -- must be (Regular) ---

		MOV	R14,#0			;Zero terminate for luck
		STRB	R14,[R1,#-1]		;Save it over the terminator
		ADR	R0,fm__regular		;Find the regular message
		BL	msgs_lookup		;Translate it nicely
		MOV	R3,R1			;Point to variant buffer
05fm__parse	LDRB	R14,[R0],#1		;Load a byte from `Regular'
		CMP	R14,#32			;Is this a control char?
		MOVCC	R14,#0			;Yes -- zero terminate then
		STRB	R14,[R3],#1		;Store in destination
		BCS	%05fm__parse		;And loop round for the rest

		MOV	R0,R2			;Point to family name again
		LDMFD	R13!,{R2,R3,R14}	;Unstack registers
		BICS	PC,R14,#C_flag		;And return to caller

		; --- Found a variant ---

10fm__parse	MOV	R14,#0			;Zero terminate for luck
		STRB	R14,[R1,#-1]		;Save it over the terminator
		MOV	R0,R2			;Point to family name again
		LDMFD	R13!,{R2,R3,R14}	;Unstack registers
		ORRS	PC,R14,#C_flag		;And return to caller

fm__regular	DCB	"fmREG:(Regular)",0

		LTORG

; --- fm__ensure ---
;
; On entry:	R0 == address of anchor and size info
;		R1 == free space required
;
; On exit:	R0 == address of first free byte in area
;		May return an error
;
; Use:		Ensures that there is the requested quantity of memory free
;		in the given block.

fm__ensure	ROUT

		STMFD	R13!,{R1,R2,R14}	;Save some registers
		LDMIB	R0,{R2,R14}		;Load used and size words
		ADD	R1,R1,R2		;Find new total size
		STR	R1,[R0,#4]		;Save this back
		ADD	R1,R1,#255		;Align up to next 256
		BIC	R1,R1,#255		;For niceness's sake
		CMP	R1,R14			;Do we already have enough?
		BHI	%50fm__ensure		;No -- allocate some more
10fm__ensure	STR	R1,[R0,#8]		;Save new total size
		LDR	R0,[R0,#0]		;Load address of block
		ADD	R0,R0,R2		;Point to first free byte
		LDMFD	R13!,{R1,R2,R14}	;And return to caller
		BICS	PC,R14,#V_flag

50fm__ensure	BL	flex_extend		;No -- then extend the block
		BCC	%10fm__ensure		;If OK, rejoin the main thing
		BL	alloc_error		;Find an error message
		LDMFD	R13!,{R1,R2,R14}	;Restore registers
		ORRS	PC,R14,#V_flag		;And return the error

		LTORG

; --- fm__string ---
;
; On entry:	R0 == pointer to anchor and size info
;		R1 == pointer to null terminated string
;
; On exit:	R0 == length of the string+1
;		May return an error
;
; Use:		Writes a string on the end of the given block.

fm__string	ROUT

		STMFD	R13!,{R0-R3,R14}	;Save some registers
		MOV	R2,R0			;Look after the anchor ptr
		MOV	R3,R1			;Keep the string address
		MOV	R0,R1			;Point to the string
		BL	str_len			;Find the length of it
		ADD	R1,R0,#1		;Allow space for terminator
		STR	R1,[R13,#0]		;Save this as return value
		MOV	R0,R2			;Point to the anchor
		BL	fm__ensure		;Make sure there's enough
		MOVVC	R1,R3			;Point to string to write
		BLVC	str_cpy			;Copy the string over
		STRVS	R0,[R13,#0]		;If it failed, return error
		LDMFD	R13!,{R0-R3,PC}		;And return to caller

		LTORG

; --- fm__align ---
;
; On entry:	R0 == pointer to anchor and size info
;
; On exit:	--
;
; Use:		Word aligns the block output address.

fm__align	ROUT

		STMFD	R13!,{R14}		;Save a register
		LDR	R14,[R0,#4]		;Load the current used offset
		ADD	R14,R14,#3		;Round up to word boundary
		BIC	R14,R14,#3		;And do the round op
		STR	R14,[R0,#4]		;Save the offset back again
		LDMFD	R13!,{PC}^		;And return to caller

		LTORG

; --- fm__fontPath ---
;
; On entry:	R0 == pointer to buffer
;
; On exit:	CS if there is a font path
;		CC otherwise
;
; Use:		Reads the environmental variable font$path and copies
;		it into the buffer given. The buffer must be at least 256
;		bytes long.

fm__fontPath	ROUT

		STMFD	R13!,{R0-R4,R14}
		MOV	R1,R0			;But buffer ptr in R1
		ADR	R0,fm__varName		;Point to the name
		MOV	R2,#256			;Length of buffer
		MOV	R3,#0			;First (and last) call
		MOV	R4,#0			;Don't expand the string
		SWI	XOS_ReadVarVal		;Read the variable
		MOV	R14,#0			;We need a NULL byte
		STRVCB	R14,[R1,R2]		;Store the terminator
		LDMFD	R13!,{R0-R4,R14}	;Load registers
		ORRVCS	PC,R14,#C_flag		;Return C set if exists
		BICVSS	PC,R14,#C_flag		;Or clear otherwise

fm__varName	DCB	"Font$Path",0

		LTORG

fm__wSpace	DCD	0

; --- fm__postFilter ---
;
; On entry:	R0 == wimp event
;		R1 == wimp poll block pointer
;
; On exit:	--
;
; Use:		Looks out for font changed events.

fm__postFilter	ROUT

		CMP	R0,#17			;Is it a message?
		CMPNE	R0,#18
		MOVNES	PC,R14			;Nope -- return
		STMFD	R13!,{R0,R14}		;Stack registers
		LDR	R0,[R1,#16]		;Load the message type
		LDR	R14,=&4A2C0		;Fonts changed message number
		CMP	R14,R0			;Is that the message?
		LDMNEFD	R13!,{R0,PC}^		;No -- return now
		LDR	R14,fm__flags		;Load flags word
		ORR	R14,R14,#fmFlag__changed
		STR	R14,fm__flags		;Store back flags
		LDMFD	R13!,{R0,PC}^		;Return to caller

		LTORG

; --- fm_init ---
;
; On entry:	--
;
; On exit:	--
;
; Use:		Initialises the font menu system.

		EXPORT	fm_init
fm_init		ROUT

		STMFD	R13!,{R0,R1,R12,R14}	;Stack some registers
		WSPACE	fm__wSpace
		MOV	R14,#0
		STR	R14,fm__flags		;No flags set yet

		; --- Set up the post filter ---

		BL	event_init		;Ensure event is ready
		ADR	R0,fm__postFilter	;Point to the handler
		MOV	R1,R12			;R12 value to pass
		BL	event_postFilter	;Add in the post filter
		SWIVS	OS_GenerateError	;Generate the error
		LDMFD	R13!,{R0,R1,R12,PC}^	;Return to caller

		LTORG

;----- Events ---------------------------------------------------------------

		^	0
fmEvent_select	#	1			;User selected a font
						;R1 == pointer to name

;----- Workspace ------------------------------------------------------------

		^	0,R12

fm__wStart	#	0

fm__block	#	4			;Address of our heap block
fm__ticks	#	8			;Tick blocks
fm__menu	#	4			;Pointer to existing menu
fm__name	#	40			;Static buffer to return name
fm__userHandler	#	4			;User handler function
fm__R10		#	4			;R10 value to call with
fm__R12		#	4			;R12 value to call with
fm__creator	#	4			;Menu creation routine
fm__flags	#	4			;Useful flags word
fm__path	#	256			;Current font path

fm__wSize	EQU	{VAR}-fm__wStart

fmFlag__changed	EQU	(1<<0)			;The fonts have changed

		AREA	|Sapphire$$LibData|,CODE,READONLY

		DCD	fm__wSize
		DCD	fm__wSpace
		DCD	256
		DCD	fm_init

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

		END
