;
; vString.s
;
; Parses validation strings for Sculptrix
;
;  1995-1998 Straylight
;

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

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

		AREA	|Module$$Code|,CODE,READONLY

; --- vString_read ---
;
; On entry:	R1 == pointer to an icon block
;
; On exit:	CS if there's a border, and
;		  R0 == border info word
;		  R4 == pointer to `inverted' flag byte
;		else CC and
;		  R0, R4 preserved
;
; Use:		Reads an icon's validation string, and extracts relevant
;		information.  The border info word contains what sort of
;		graphics we have to plot around the icon, and any special
;		options thrown in.  A string (for group borders etc.) is
;		copied into the misc buffer if one was found.
;
;		The syntax of a Sculptrix validation string is as follows:
;
;		  `xb'<type>[<flags>][`,'<text>]
;
;		The <type> is a letter which determines what sort of border
;		is to be drawn.  The <flags> modify the style of the border
;		slightly.  Note that if the <type> is uppercase, then the
;		border is inverted.  The <text> is only required for group
;		boxes (type `g').  An unknown <type> causes the icon to be
;		ignored.  Unknown <flags> are ignored.  If no text is
;		specified, a null string is assumed by default.  Spaces
;		are allowed in various sensible places.

		EXPORT	vString_read
vString_read	ROUT

		STMFD	R13!,{R0-R4,R14}	;Save some registers

		; --- Find the validation string first ---

		MOV	R2,#0			;First call, this is
00		MOV	R0,#'x'			;Find the validation string
		BL	vString_find		;Try to find the string
		BCC	%90vString_read		;Can't find a Sculptrix cmd
		LDRB	R14,[R2,#1]		;Load the subcommand code

	      [	:LNOT::DEF:only_new_commands
		SUB	R4,R14,#'0'		;Convert to a digit
		CMP	R4,#10			;Is this recognised?
		BCC	%50vString_read		;Yes -- deal with it
	      ]

		ORR	R14,R14,#&20		;Make the command lowercase

	      [ :LNOT::DEF:only_new_commands
		CMP	R14,#'g'		;Is it a group command?
		BEQ	%60vString_read		;Yes -- deal with it
	      ]

		CMP	R14,#'s'		;Is it a text+sprite?
		BEQ	%70vString_read		;Yes -- deal with that too

		CMP	R14,#'b'		;Is it the main `b' command?
		BNE	%b00			;No -- loop back for more

		; --- Handle the new `xb' command ---

		MOV	R14,#0			;Initially terminate string
		STRB	R14,sculpt_misc		;To avoid nasty problems
		ADD	R2,R2,#2		;Skip past the command chars

00		LDRB	R3,[R2],#1		;Load a byte from the string
		CMP	R3,#&20			;Is it a space character?
		BEQ	%b00			;Yes -- keep looking then
		CMP	R3,#';'			;End of the command?
		CMPNE	R3,#&1F			;Of of the whole string?
		BLS	%90vString_read		;End of string -- abort now

		ORR	R0,R3,#&20		;Make the char lowercase
		ADR	R1,vString__cnvTbl	;Point to the table
		BL	vString__lookup		;Look up letter in the table
		BCC	%90vString_read		;Not found -- give up then
		MOV	R4,R0			;Get the command code

		TST	R3,#&20			;Is the command uppercase?
		EOREQ	R4,R4,#vsFlag_invert	;Yes -- invert the border
		SUB	R3,R2,#1		;Remember this offset

		; --- Now read in the flags ---

		ADR	R1,vString__flags	;Point to the flags table

00		LDRB	R14,[R2],#1		;Load a byte from the string
		CMP	R14,#&20		;Is it a space character?
		BEQ	%b00			;Yes -- keep looking then
		CMP	R14,#';'		;End of the command?
		CMPNE	R14,#&1F		;Of of the whole string?
		BLS	%f05			;End of string -- return
		CMP	R14,#','   		;Is it a comma?
		BEQ	%f00			;Yes -- handle the text then

		ORR	R0,R14,#&20		;Make character lowercase
		BL	vString__lookup		;Do the lookup
		EORCS	R4,R4,R0		;And merge in the flag
		B	%b00			;Keep going until done

		; --- Copy the text over and exit ---

00		BL	vString__copy		;Copy the text over, please
		B	%80vString_read		;Now return this to caller

		; --- Deal with an empty string ---

05		AND	R14,R4,#&0000FF00	;Extract the type code
		CMP	R14,#vsCode_group	;Is this a group box?
		MOVEQ	R4,#vsBrd_ridge+vsFlag_fade+vsFlag_invert
		LDREQ	R14,sculpt_flags	;Load the flags word
		TSTEQ	R14,#scFlag_acorn	;Acorn style group box?
		BICEQ	R4,R4,#vsFlag_invert	;No -- don't invert it then
		B	%80vString_read		;Now return this to caller

		; --- Conversion tables ---

vString__cnvTbl	DCD	'a',vsBrd_action + vsFlag_slab
		DCD	'd',vsBrd_default + vsFlag_slab
		DCD	'i',vsBrd_action + vsFlag_invert
		DCD	'p',vsBrd_action + vsFlag_invert + vsFlag_fade
		DCD	'r',vsBrd_ridge
		DCD	'c',vsBrd_ridge + vsFlag_invert
		DCD	'w',vsBrd_write
		DCD	'o',vsBrd_offset
		DCD	'g',vsCode_group
		DCD	-1

vString__flags	DCD	'f',vsFlag_fade
		DCD	'i',vsFlag_invert
		DCD	-1

		; --- Handle old-style `x<digit>' command ---

	      [ :LNOT::DEF:only_new_commands

50vString_read	MOV	R3,R2			;Remember this position
		ADR	R14,vString__oldTbl	;Point to the table
		LDR	R4,[R14,R4,LSL #2]	;Load the appropriate word
		CMP	R4,#-1			;Is there a zero there?
		BEQ	%90vString_read		;Yes -- give up then
		LDRB	R14,[R3,#0]		;Load the `X' character
		TST	R14,#&20		;Is it uppercase?
		EOREQ	R4,R4,#vsFlag_invert	;Yes -- invert the icon
		B	%80vString_read		;Now return this to caller

vString__oldTbl	DCD	vsCode_simple + vsBrd_action + vsFlag_slab
		DCD	vsCode_simple + vsBrd_ridge
		DCD	vsCode_simple + vsBrd_default + vsFlag_slab
		DCD	vsCode_simple + vsBrd_offset
		DCD	vsCode_simple + vsBrd_action
		DCD	-1			;Group box title -- withdrawn
		DCD	-1			;Group box title -- withdrawn
		DCD	vsCode_simple + vsBrd_write
		DCD	vsCode_simple + vsBrd_action + vsFlag_fade
		DCD	-1

	      ]

		; --- Handle old-style `xg' command ---

	      [ :LNOT::DEF:only_new_commands

60vString_read	ADD	R3,R2,#1		;Point to the `G'
		ADD	R2,R2,#3		;Skip onto the text
		MOV	R4,#vsCode_group	;Get a group title word
		BL	vString__copy		;Copy the text over, please
		B	%80vString_read		;Now return this to caller

	      ]

		; --- Handle `xs' text+sprite command ---

70vString_read	ADD	R3,R2,#1		;Point to the `S'
		ADD	R2,R2,#2		;Skip onto the text
		MOV	R4,#vsCode_tns		;Get the mystic word
		BL	vString__copy		;Copy the text over, please
		B	%80vString_read		;Now return this to caller

		; --- Return values to caller ---

80vString_read	STR	R4,[R13,#4*0]		;Store the information word
		STR	R3,[R13,#4*4]		;And the invert flag address
		LDMFD	R13!,{R0-R4,R14}	;Restore registers
		ORRS	PC,R14,#C_flag		;And return with C set

90vString_read	LDMFD	R13!,{R0-R4,R14}	;Restore registers
		BICS	PC,R14,#C_flag		;And return with C clear

		LTORG

; --- vString__copy ---
;
; On entry:	R0 == border type code
;		R2 == pointer to tail of validation string
;
; On exit:	R2 moved on
;
; Use:		Copies the tail of the validation string into the misc
;		buffer, transforming escape sequences correctly.

vString__copy	ROUT

		STMFD	R13!,{R0,R14}		;Save some registers
		ADR	R0,sculpt_misc		;Point to the buffer

00		LDRB	R14,[R2],#1		;Load the next byte out
		CMP	R14,#';'		;Is this the end?
		CMPNE	R14,#&1F		;Check for end of string
		BLS	%f00			;Yes -- skip onwards then

		CMP	R14,#'\'		;Is this an escape?
		STRNEB	R14,[R0],#1		;Nothing special -- store
		BNE	%b00			;And loop back round

		LDRB	R14,[R2],#1		;Load the next byte out
		CMP	R14,#&20		;Check for end of string
		STRCSB	R14,[R0],#1		;Nothing special -- store
		BCS	%b00			;And loop back round

00		MOV	R14,#0			;Zero terminate the string
		STRB	R14,[R0],#1		;Store in the buffer
		LDMFD	R13!,{R0,PC}^		;Return when done

		LTORG

; --- vString__lookup ---
;
; On entry:	R0 == word to look for
;		R1 == pointer to table
;
; On exit:	CS if found, and
;		  R0 == word from table
;		else CC and
;		  R0 corrupted
;
; Use:		Looks a word in a table, and returns the corresponding other
;		word.

vString__lookup	ROUT

		STMFD	R13!,{R1,R14}		;Save some registers
00		LDR	R14,[R1],#8		;Load the next word
		CMP	R14,#-1			;Is this the end?
		CMPNE	R14,R0			;Do these match?
		BNE	%b00			;Neither -- go back then
		CMP	R14,R0			;Which one was it?
		LDREQ	R0,[R1,#-4]		;Match -- load previous word
		LDMFD	R13!,{R1,R14}		;Restore registers
		ORREQS	PC,R14,#C_flag		;Return C set if found
		BICNES	PC,R14,#C_flag		;Return C clear if not

		LTORG

; --- vString_find ---
;
; On entry:	R0 == character to find in block (not case-sensitive)
;		R1 == pointer to icon block
; 		R2 == old pointer to search from, or 0
;
; On exit:	R0 == character forced to lower case
;		CS if found, and
;		  R2 points to command string
;		else CC and
;		  R2 corrupted
;
; Use:		Tries to find a validation string command in the given
;		icon block.

		EXPORT	vString_find
vString_find	ROUT

		BIC	R14,R14,#C_flag		;Assume we won't find it
		STMFD	R13!,{R3,R14}		;Preserve for later use

		; --- Ensure the icon is text and indirected ---

		LDR	R3,[R1,#16]		;Get flags word
		TST	R3,#1<<23		;Is it deleted?
		MOVEQ	R14,#&100		;Can't put 101 in one instr
		ORREQ	R14,R14,#&01		;Check indirect and text
		ANDEQ	R3,R3,R14		;Mask the bits off
		CMPEQ	R3,R14			;Were they both set?
		LDMNEFD	R13!,{R3,PC}^		;No -- return huffily

		; --- Find the validation string ---

		LDR	R3,[R1,#24]		;Get pointer to valid string
		CMP	R3,#-1			;Is it empty?
		LDMEQFD	R13!,{R3,PC}^		;No -- return huffily

		; --- Start from the right index ---

		ORR	R0,R0,#&20		;Make valid char lower case
		CMP	R2,#0			;Is it the start?
		ADDNE	R2,R2,#1		;No -- miss out one char
		BNE	%30vString_find		;And skip this command
		MOV	R2,R3			;Start at the beginning

		; --- Check the first char of a validation string ---

10vString_find	LDRB	R14,[R2],#1		;Get a byte from string
		ORR	R3,R14,#&20		;Make lower case
		CMP	R3,R0			;Is it a match?
		SUBEQ	R2,R2,#1		;Point back to character
		LDMEQFD	R13!,{R3,R14}		;And return
		ORREQS	PC,R14,#C_flag		;Set C on exit for this
		MOV	R3,#0			;Not an excaped character

		; --- Skip ahead to the next validation string ---

20vString_find	CMP	R14,#' '		;Is it a control char?
		LDMCCFD	R13!,{R3,PC}^		;Yes -- return
		CMP	R3,#1			;Are we escaping?
		MOVEQ	R3,#0			;Yes -- done that now
		BEQ	%30vString_find		;So skip this bit
		CMP	R14,#';'		;Is it a semicolon?
		BEQ	%10vString_find		;Yes -- try a new command
		CMP	R14,#'\'		;Is it a backslash?
		MOVEQ	R3,#1			;Yes -- escape next char
30vString_find	LDRB	R14,[R2],#1		;Get another character
		B	%20vString_find		;And try again

		LTORG

;----- Border codes and flags -----------------------------------------------

		^	0
vsCode_simple	#	&0100			;A simple border
vsCode_group	#	&0100			;A group box border
vsCode_tns	#	&0100			;Text+sprite icon

		^	0
vsBrd_action	#	1			;Standard action button
vsBrd_default	#	1			;Default action button
vsBrd_ridge	#	1			;A ridge type border
vsBrd_write	#	1			;A writable border
vsBrd_offset	#	1			;Offset pressed-in border

vsFlag_invert	EQU	(1<<31)			;Icon border is inverted
vsFlag_fade	EQU	(1<<30)			;Icon border is faded
vsFlag_slab	EQU	(1<<29)			;Icon may be slabbed

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

		END
