; > Territories.Source

; History
; 28 Jan 1999	JB	wrote module base
; 29 Jan 1999	JB	changed to use paths
;			added character tables
; 04 Feb 1999	JB	wrote much of territory_convertdateandtime
; 05 Feb 1999	JB	continued with territory_convertdateandtime
; 06 Feb 1999	JB	finished territory_convertdateandtime
;			wrote territory_convertstandard*
; 08 Feb 1999	JB	wrote territory_converttimetoordinals
; 10 Feb 1999	JB	wrote territory_converttimestringtoordinals
; 11 Feb 1999	JB	wrote territory_convertordinalstotime
;			wrote territory_selectkeyboardhandler
; 15 Feb 1999	JB	wrote territory_collate
; 18 Feb 1999	JB	wrote territory_readsymbols
;			wrote territory_readcalendarinformation
;			wrote territory_nametonumber
;			wrote territory_transformstring
; 20 Feb 1999	JB	removed help_and_command_keyword_table (was null)
; 25 Jan 2000	JB	altered to use AAsm and rearranged files
; 12 Feb 2000	JB	fixed divide to round downwards

;
; Misc stuff
;

; lower case registers
r0	RN		0
r1	RN		1
r2	RN		2
r3	RN		3
r4	RN		4
r5	RN		5
r6	RN		6
r7	RN		7
r8	RN		8
r9	RN		9
r10	RN		10
r11	RN		11
r12	RN		12
r13	RN		13
r14	RN		14
r15	RN		15
pc 	RN		15
f0	FN		0
f1	FN		1

; workspace offsets
		^	0
Entry_Table	#	43 * 4
Time		#	8
Ordinal_Buffer	#	0
Centiseconds	#	4
Seconds		#	4
Minutes		#	4
Hours		#	4
Day		#	4
Month		#	4
Year		#	4
WeekDay		#	4
YearDay		#       4
Workspace_Size	#	0

; swi numbers
XOS_Module				*	&2001e
XOS_ReadUnsigned			*	&20021
XOS_ConvertCardinal4			*	&200d8
XTerritory_Register			*	&63041
XTerritory_Deregister			*	&63042
XTerritory_ReadCurrentTimeZone		*	&63048
XTerritory_ConvertTimeToUTCOrdinals	*	&63049
XTerritory_ConvertOrdinalsToTime	*	&63051
XTerritory_ReadCalendarInformation	*	&6305f
XTerritory_NameToNumber			*	&63060

;
; Module header
;

start
	DCD		0	;start_code
	DCD		initialisation_code - start
	DCD		finalisation_code - start
	DCD		service_call_handler - start
	DCD		title_string - start
	DCD		help_string - start
	DCD		help_and_command_keyword_table - start

;
; Title and help strings
;

title_string
	DCB		MODULE_NAME
	DCB		0

help_string
	DCB		MODULE_TITLE
	DCB		9
	DCB		MODULE_VERSION
	DCB		0

	ALIGN

;
; Initialisation code
;

initialisation_code				; 1-207
	STMFD		r13!, {r14}

	LDR		r0, [r12]
	TEQ		r0, #0
	BNE		ic_allocated

	MOV		r0, #6
	MOV		r3, #Workspace_Size
	SWI		XOS_Module		; Claim (1-233)
	LDMVSFD		r13!, {pc}
	STR		r2, [r12]

ic_allocated
	LDR		r12, [r12]
	BL		territory_register
	LDMVSFD		r13!, {pc}

	LDMFD		r13!, {pc}^

;
; Finalisation code
;

finalisation_code				; 1-209
	STMFD		r13!, {r14}

	MOV		r0, #(TERRITORY_NUMBER)
	SWI		XTerritory_Deregister	; 3-795
	LDMVSFD		r13!, {pc}

	LDMFD		r13!, {pc}^

;
; Service call handler
;

service_call_handler				; 1-210
	TEQ		r1, #&64		; Service_TerritoryManagerLoaded (3-790)
	MOVNES		pc, r14

	STMFD		r13!, {r14}

	LDR		r12, [r12]
	BL		territory_register
	LDMVSFD		r13!, {pc}

	LDMFD		r13!, {pc}^

;
; Help and command keyword table
;

help_and_command_keyword_table
	DCB		MODULE_NAME
	DCB		0
	ALIGN
	DCD		0			; no code
	DCD		0			; information word
	DCD		0			; syntax message
	DCD		about - start		; help offset
	DCB		0

about
	DCB		ABOUT_MESSAGE
	DCB		0
	ALIGN

;
; Territory manager related
;

territory_register
	STMFD		r13!, {r0-r2, r14}

	ADRL		r1, territory_readtimezones			; &4304A
	STR		r1, [r12, #00]
	ADRL		r1, territory_convertdateandtime		; &4304B
	STR		r1, [r12, #04]
	ADRL		r1, territory_convertstandarddateandtime	; &4304C
	STR		r1, [r12, #08]
	ADRL		r1, territory_convertstandarddate		; &4304D
	STR		r1, [r12, #12]
	ADRL		r1, territory_convertstandardtime		; &4304E
	STR		r1, [r12, #16]
	ADRL		r1, territory_converttimetoordinals		; &4304F
	STR		r1, [r12, #20]
	ADRL		r1, territory_converttimestringtoordinals	; &43050
	STR		r1, [r12, #24]
	ADRL		r1, territory_convertordinalstotime		; &43051
	STR		r1, [r12, #28]
	ADRL		r1, territory_alphabet				; &43052
	STR		r1, [r12, #32]
	ADRL		r1, territory_alphabetidentifier		; &43053
	STR		r1, [r12, #36]
	ADRL		r1, territory_selectkeyboardhandler		; &43054
	STR		r1, [r12, #40]
	ADRL		r1, territory_writedirection			; &43055
	STR		r1, [r12, #44]
	ADRL		r1, territory_characterpropertytable		; &43056
	STR		r1, [r12, #48]
	ADRL		r1, territory_lowercasetable			; &43057
	STR		r1, [r12, #52]
	ADRL		r1, territory_uppercasetable			; &43058
	STR		r1, [r12, #56]
	ADRL		r1, territory_controltable			; &43059
	STR		r1, [r12, #60]
	ADRL		r1, territory_plaintable			; &4305A
	STR		r1, [r12, #64]
	ADRL		r1, territory_valuetable			; &4305B
	STR		r1, [r12, #68]
	ADRL		r1, territory_representationtable		; &4305C
	STR		r1, [r12, #72]
	ADRL		r1, territory_collate				; &4305D
	STR		r1, [r12, #76]
	ADRL		r1, territory_readsymbols			; &4305E
	STR		r1, [r12, #80]
	ADRL		r1, territory_readcalendarinformation		; &4305F
	STR		r1, [r12, #84]
	ADRL		r1, territory_nametonumber			; &43060
	STR		r1, [r12, #88]
	ADRL		r1, territory_transformstring			; &43061
	STR		r1, [r12, #92]
	ADRL		r1, territory_reserved				; &43062
	STR		r1, [r12, #96]
	STR		r1, [r12, #100]				; &43063
	STR		r1, [r12, #104]				; &43064
	STR		r1, [r12, #108]				; &43065
	STR		r1, [r12, #112]				; &43066
	STR		r1, [r12, #116]				; &43067
	STR		r1, [r12, #120]				; &43068
	STR		r1, [r12, #124]				; &43069
	STR		r1, [r12, #128]				; &4306A
	STR		r1, [r12, #132]				; &4306B
	STR		r1, [r12, #136]				; &4306C
	STR		r1, [r12, #140]				; &4306D
	STR		r1, [r12, #144]				; &4306E
	STR		r1, [r12, #148]				; &4306F
	STR		r1, [r12, #152]				; &43070
	STR		r1, [r12, #156]				; &43071
	STR		r1, [r12, #160]				; &43072
	STR		r1, [r12, #164]				; &43073
	STR		r1, [r12, #168]				; &43074

	MOV		r0, #TERRITORY_NUMBER
	MOV		r1, r12
	MOV		r2, r12
	SWI		XTerritory_Register
	ADDVS		r13, r13, #4
	LDMVSFD		r13!, {r1-r2, pc}

	LDMFD		r13!, {r0-r2, pc}^

;
; Territory module SWIs
;

territory_readtimezones				; 3-806
	ADR		r0, timezone
	ADR		r1, dstzone
	LDR		r2, timeoffset
	LDR		r3, dstoffset

	MOVS		pc, r14

timezone
	DCB		TIME_ZONE
	DCB		0
dstzone
	DCB		DST_ZONE
	DCB		0
	ALIGN
timeoffset
	DCD		TIME_OFFSET
dstoffset
	DCD		DST_OFFSET

;

territory_convertdateandtime			; 3-807
	STMFD		r13!, {r5-r11, r14}

	MOV		r7, r1			; pointer to 5 byte UTC time
	MOV		r8, r2			; pointer to buffer
	MOV		r9, r2			; pointer to terminating 0 in buffer
	MOV		r10, r3			; number of bytes free in buffer
	MOV		r11, r4			; pointer to format string
	MOV		r5, r4			; pointer to format string position

	SWI		XTerritory_ReadCurrentTimeZone	; 3-801
	LDMVSFD		r13!, {r5-r11, pc}
	MOV		r6, r0			; pointer to name of current time zone

	LDR		r2, [r7]		; add time zone to convert UTC to local time
	LDRB		r3, [r7, #4]
	ADDS		r2, r2, r1
	ADC		r3, r3, #0
	STR		r2, [r12, #(Time + 0)]
	STRB		r3, [r12, #(Time + 4)]

	ADD		r1, r12, #Time		; convert 5 byte time to more useful ordinals
	ADD		r2, r12, #Ordinal_Buffer
	SWI		XTerritory_ConvertTimeToUTCOrdinals	; 3-802
	LDMVSFD		r13!, {r5-r11, pc}

tcdat_loop
	CMP		r10, #1			; check space in buffer
	BLT		tcdat_buffer_overflow

	LDRB		r0, [r5], #1		; get a byte

	TEQ		r0, #"%"		; format field
	BEQ		tcdat_field

	STRB		r0, [r9], #1		; other - add to buffer
	SUB		r10, r10, #1		; decrement free space

	CMP		r0, #32			; check for terminator (<32)
	BGE		tcdat_loop

	MOV		r0, r8			; tidy up & exit
	SUB		r1, r9, #1
	MOV		r2, r10
	MOV		r3, r11
	MOV		r4, r3

	LDMFD		r13!, {r5-r11, pc}^

tcdat_field						; 1-402
	LDRB		r0, [r5], #1		; first byte

	TEQ		r0, #"0"		; %0 - insert zero byte
	MOVEQ		r0, #0
	STREQB		r0, [r9], #1
	SUBEQ		r10, r10, #1
	BEQ		tcdat_loop

	TEQ		r0, #"%"		; %% - insert a %
	STREQB		r0, [r9], #1
	SUBEQ		r10, r10, #1
	BEQ		tcdat_loop

        TEQ		r0, #"z"		; z - without leading zeros
        TEQNE		r0, #"Z"
        MOVEQ		r4, #1			; flag z
        MOVNE		r4, #0
        LDREQB		r0, [r5], #1		; get a replacement byte

        CMP		r0, #32			; unexpected termination
	BLS		tcdat_unknown_field

	LDRB		r1, [r5], #1		; second byte
        CMP		r1, #32			; unexpected termination
	BLS		tcdat_unknown_field

	ORR		r0, r0, #32		; convert to lowercase
	ORR		r1, r1, #32

	TEQ		r0, #"c"		; cs
	TEQEQ		r1, #"s"
	LDREQ		r0, [r12, #Centiseconds]
	BEQ		tcdat_add_number2

	TEQ		r0, #"s"		; se
	TEQEQ		r1, #"e"
	LDREQ		r0, [r12, #Seconds]
	BEQ		tcdat_add_number2

	TEQ		r0, #"m"		; mi
	TEQEQ		r1, #"i"
	LDREQ		r0, [r12, #Minutes]
	BEQ		tcdat_add_number2

	TEQ		r0, #"1"		; 12
	TEQEQ		r1, #"2"
	BNE		tcdat_skip_12
	LDR		r0, [r12, #Hours]
	CMP		r0, #12			; convert to 12-hour
	SUBGT		r0, r0, #12
	TEQ		r0, #0			; 0h => 12h
	MOVEQ		r0, #12
	B		tcdat_add_number2
tcdat_skip_12

	TEQ		r0, #"2"		; 24
	TEQEQ		r1, #"4"
	LDREQ		r0, [r12, #Hours]
	BEQ		tcdat_add_number2

	TEQ		r0, #"a"		; am
	TEQEQ		r1, #"m"
	; am/pm not implemented - not used much anyway
	BEQ		tcdat_loop

	TEQ		r0, #"p"		; pm
	TEQEQ		r1, #"m"
	; am/pm not implemented - not used much anyway
	BEQ		tcdat_loop

	TEQ		r0, #"w"		; we
	TEQEQ		r1, #"e"
	BNE		tcdat_skip_we
	LDR		r1, [r12, #WeekDay]
	TEQ		r1, #1			; !!!
	ADREQL		r0, sunday
	TEQ		r1, #2
	ADREQL		r0, monday
	TEQ		r1, #3
	ADREQL		r0, tuesday
	TEQ		r1, #4
	ADREQL		r0, wednesday
	TEQ		r1, #5
	ADREQL		r0, thursday
	TEQ		r1, #6
	ADREQL		r0, friday
	TEQ		r1, #7
	ADREQL		r0, saturday
	B		tcdat_add_string
tcdat_skip_we

	TEQ		r0, #"w"		; w3
	TEQEQ		r1, #"3"
	BNE		tcdat_skip_w3
	LDR		r1, [r12, #WeekDay]
	TEQ		r1, #1			; !!!
	ADREQL		r0, sun
	TEQ		r1, #2
	ADREQL		r0, mon
	TEQ		r1, #3
	ADREQL		r0, tue
	TEQ		r1, #4
	ADREQL		r0, wed
	TEQ		r1, #5
	ADREQL		r0, thu
	TEQ		r1, #6
	ADREQL		r0, fri
	TEQ		r1, #7
	ADREQL		r0, sat
	B		tcdat_add_string
tcdat_skip_w3

	TEQ		r0, #"w"		; wn
	TEQEQ		r1, #"n"
	BNE		tcdat_skip_wn
	LDR		r0, [r12, #WeekDay]
	SUB		r0, r0, #1		; convert to mon = 1, sun = 7
	TEQ		r0, #0
	MOVEQ		r0, #7
	B		tcdat_add_number1
tcdat_skip_wn

	TEQ		r0, #"d"		; dy
	TEQEQ		r1, #"y"
	LDREQ		r0, [r12, #Day]
	BEQ		tcdat_add_number2

	TEQ		r0, #"s"		; st
	TEQEQ		r1, #"t"
	; st field not implemented
	BEQ		tcdat_loop

	TEQ		r0, #"m"		; mo
	TEQEQ		r1, #"o"
	BNE		tcdat_skip_mo
	LDR		r1, [r12, #Month]
	TEQ		r1, #1
	ADREQL		r0, january
	TEQ		r1, #2
	ADREQL		r0, february
	TEQ		r1, #3
	ADREQL		r0, march
	TEQ		r1, #4
	ADREQL		r0, april
	TEQ		r1, #5
	ADREQL		r0, may
	TEQ		r1, #6
	ADREQL		r0, june
	TEQ		r1, #7
	ADREQL		r0, july
	TEQ		r1, #8
	ADREQL		r0, august
	TEQ		r1, #9
	ADREQL		r0, september
	TEQ		r1, #10
	ADREQL		r0, october
	TEQ		r1, #11
	ADREQL		r0, november
	TEQ		r1, #12
	ADREQL		r0, december
	B		tcdat_add_string
tcdat_skip_mo

	TEQ		r0, #"m"		; m3
	TEQEQ		r1, #"3"
	BNE		tcdat_skip_m3
	LDR		r1, [r12, #Month]
	TEQ		r1, #1
	ADREQL		r0, jan
	TEQ		r1, #2
	ADREQL		r0, feb
	TEQ		r1, #3
	ADREQL		r0, mar
	TEQ		r1, #4
	ADREQL		r0, apr
	TEQ		r1, #5
	ADREQL		r0, may3
	TEQ		r1, #6
	ADREQL		r0, jun
	TEQ		r1, #7
	ADREQL		r0, jul
	TEQ		r1, #8
	ADREQL		r0, aug
	TEQ		r1, #9
	ADREQL		r0, sep
	TEQ		r1, #10
	ADREQL		r0, oct
	TEQ		r1, #11
	ADREQL		r0, nov
	TEQ		r1, #12
	ADREQL		r0, dec
	B		tcdat_add_string
tcdat_skip_m3

	TEQ		r0, #"m"		; mn
	TEQEQ		r1, #"n"
	LDREQ		r0, [r12, #Month]
	BEQ		tcdat_add_number2

	TEQ		r0, #"c"		; ce
	TEQEQ		r1, #"e"
	LDREQ		r0, [r12, #Year]
	MOVEQ		r1, #100
	BLEQ		divide
	BEQ		tcdat_add_number2

	TEQ		r0, #"y"		; yr
	TEQEQ		r1, #"r"
	LDREQ		r0, [r12, #Year]
	MOVEQ		r3, r0
	MOVEQ		r1, #100
	BLEQ		divide
	MULEQ		r2, r1, r0		; work out the remainder
	SUBEQ		r0, r3, r2
	BEQ		tcdat_add_number2

	TEQ		r0, #"w"		; wk
	TEQEQ		r1, #"k"
	BNE		tcdat_skip_wk
	LDR		r0, [r12, #YearDay]
	LDR		r1, [r12, #WeekDay]
	SUBS		r1, r1, #1		; compensate for sun = 1
	MOVEQ		r1, #7
	SUB		r1, r0, r1
	ADD		r0, r1, #7
	MOV		r1, #7
	BL		divide
	B		tcdat_add_number2
tcdat_skip_wk

	TEQ		r0, #"d"		; dn
	TEQEQ		r1, #"n"
	LDREQ		r0, [r12, #YearDay]
	BEQ		tcdat_add_number3

	TEQ		r0, #"t"		; tz
	TEQEQ		r1, #"z"
	MOVEQ		r0, r6
	BEQ		tcdat_add_string
						; drop through
tcdat_unknown_field
	ADRL		r0, unknown_field
	LDMFD		r13!, {r5-r11, r14}
	ORRS		pc, r14, #&10000000

tcdat_buffer_overflow
	ADRL		r0, buffer_overflow
	LDMFD		r13!, {r5-r11, r14}
	ORRS		pc, r14, #&10000000

tcdat_add_number2
	TEQ		r4, #0			; insert leading 0 if necessary
	BNE		tcdat_add_number1
	CMP		r0, #10
	MOVLT		r1, #"0"
	STRLTB		r1, [r9], #1
	SUBLT		r10, r10, #1		; decrement free space
						; dropped into by number2
tcdat_add_number1
	MOV		r1, r9
	MOV		r2, r10
	SWI		XOS_ConvertCardinal4	; 1-469
	LDMVSFD		r13!, {r5-r11, pc}
	MOV		r9, r1
	MOV		r10, r2

	B		tcdat_loop

tcdat_add_number3
	TEQ		r4, #0			; insert leading 0s if necessary
	BNE		tcdat_add_number1
	CMP		r0, #100
	BGE		tcdat_add_number1
	MOV		r1, #"0"
	STRB		r1, [r9], #1
	SUB		r10, r10, #1		; decrement free space
	CMP		r0, #10
	BGE		tcdat_add_number1
	CMP		r10, #1			; check space in buffer
	BLT		tcdat_buffer_overflow
	MOV		r1, #"0"
	STRB		r1, [r9], #1
	SUB		r10, r10, #1		; decrement free space
	B		tcdat_add_number1

tcdat_add_string
	LDRB		r1, [r0], #1		; source byte
	CMP		r1, #32
	BLT		tcdat_loop

	STRB		r1, [r9], #1		; destination buffer
	SUB		r10, r10, #1
	CMP		r10, #1			; check space in buffer
	BLT		tcdat_buffer_overflow
	B		tcdat_add_string

monday	DCB		MONDAY
	DCB		0
tuesday DCB		TUESDAY
	DCB		0
wednesday DCB		WEDNESDAY
	DCB		0
thursday DCB		THURSDAY
	DCB		0
friday	DCB		FRIDAY
	DCB		0
saturday DCB		SATURDAY
	DCB		0
sunday	DCB		SUNDAY
	DCB		0

mon	DCB		MON
	DCB		0
tue	DCB		TUE
	DCB		0
wed	DCB		WED
	DCB		0
thu	DCB		THU
	DCB		0
fri	DCB		FRI
	DCB		0
sat	DCB		SAT
	DCB		0
sun	DCB		SUN
	DCB		0

january DCB		JANUARY
	DCB		0
february DCB		FEBRUARY
	DCB		0
march	DCB		MARCH
	DCB		0
april	DCB		APRIL
	DCB		0
may	DCB		MAY
	DCB		0
june	DCB		JUNE
	DCB		0
july	DCB		JULY
	DCB		0
august	DCB		AUGUST
	DCB		0
september DCB		SEPTEMBER
	DCB		0
october DCB		OCTOBER
	DCB		0
november DCB		NOVEMBER
	DCB		0
december DCB		DECEMBER
	DCB		0

jan	DCB		JAN
	DCB		0
feb	DCB		FEB
	DCB		0
mar	DCB		MAR
	DCB		0
apr	DCB		APR
	DCB		0
may3	DCB		MAY
	DCB		0
jun	DCB		JUN
	DCB		0
jul	DCB		JUL
	DCB		0
aug	DCB		AUG
	DCB		0
sep	DCB		SEP
	DCB		0
oct	DCB		OCT
	DCB		0
nov	DCB		NOV
	DCB		0
dec	DCB		DEC
	DCB		0
	ALIGN

;

territory_convertstandarddateandtime		; 3-809
	STMFD		r13!, {r3, r4, r14}

	ADR		r4, dateandtime
	BL		territory_convertdateandtime

	LDMVSFD		r13!, {r3, r4, pc}
	LDMFD		r13!, {r3, r4, pc}^

dateandtime
	DCB		DATEANDTIME
	DCB		0
	ALIGN

;

territory_convertstandarddate			; 3-811
	STMFD		r13!, {r3, r4, r14}

	ADR		r4, date
	BL		territory_convertdateandtime

	LDMVSFD		r13!, {r3, r4, pc}
	LDMFD		r13!, {r3, r4, pc}^

date
	DCB		DATE
	DCB		0
	ALIGN

;

territory_convertstandardtime			; 3-813
	STMFD		r13!, {r3, r4, r14}

	ADR		r4, time
	BL		territory_convertdateandtime

	LDMVSFD		r13!, {r3, r4, pc}
	LDMFD		r13!, {r3, r4, pc}^

time
	DCB		TIME
	DCB		0
	ALIGN

;

territory_converttimetoordinals		; 3-815
	STMFD		r13!, {r1-r4, r14}

	MOV		r4, r1			; pointer to UTC time
	MOV		r5, r2			; pointer to buffer

	SWI		XTerritory_ReadCurrentTimeZone	; 3-801
	LDMVSFD		r13!, {r1-r4, pc}

	LDR		r2, [r4]		; add time zone to convert UTC to local time
	LDRB		r3, [r4, #4]
	ADDS		r2, r2, r1
	ADC		r3, r3, #0
	STR		r2, [r12, #(Time + 0)]
	STRB		r3, [r12, #(Time + 4)]

	ADD		r1, r12, #Time		; convert 5 byte time to more useful ordinals
	MOV		r2, r5
	SWI		XTerritory_ConvertTimeToUTCOrdinals	; 3-802
	LDMVSFD		r13!, {r1-r4, pc}

	LDR		r1, [r5, #28]		; correct day of week
	SUB		r1, r1, #1
	TEQ		r1, #0
	MOVEQ		r1, #7
	STR		r1, [r5, #28]

	LDMFD		r13!, {r1-r4, pc}^

;

territory_converttimestringtoordinals		; 3-817
	STMFD		r13!, {r1-r7, r14}

	MOV		r0, #-1
	STR		r0, [r3, #0]
	STR		r0, [r3, #4]
	STR		r0, [r3, #8]
	STR		r0, [r3, #12]
	STR		r0, [r3, #16]
	STR		r0, [r3, #20]
	STR		r0, [r3, #24]

	MOV		r4, r1			; reason code
	MOV		r5, r2			; time STRing

	TEQ		r4, #1			; %24:%mi:%se
	BEQ		tctsto_time

	TEQ		r4, #2			; %w3, %dy-%m3-%ce%yr
	TEQNE		r4, #3			; %w3, %dy-%m3-%ce%yr.%24:%mi:%se
	BEQ		tctsto_date

	ADRL		r0, unknown_format
	LDMFD		r13!, {r1-r7, r14}
	ORRS		pc, r14, #&10000000

tctsto_date
	LDRB		r0, [r5], #1		; skip %w3, 
	CMP		r0, #" "
	BLT		tctsto_bad_string
	BNE		tctsto_date

	MOV		r0, #10
	MOV		r1, r5
	SWI		XOS_ReadUnsigned	; 1-448
	LDMVSFD		r13!, {r1-r7, pc}
	STR		r2, [r3, #16]		; day

	ADD		r5, r1, #1		; skip -

	ADRL		r0, jan
	MOV		r2, #1
	BL		tctsto_compare

	ADRL		r0, feb
	MOV		r2, #2
	BL		tctsto_compare

	ADRL		r0, mar
	MOV		r2, #3
	BL		tctsto_compare

	ADRL		r0, apr
	MOV		r2, #4
	BL		tctsto_compare

	ADRL		r0, may3
	MOV		r2, #5
	BL		tctsto_compare

	ADRL		r0, jun
	MOV		r2, #6
	BL		tctsto_compare

	ADRL		r0, jul
	MOV		r2, #7
	BL		tctsto_compare

	ADRL		r0, aug
	MOV		r2, #8
	BL		tctsto_compare

	ADRL		r0, sep
	MOV		r2, #9
	BL		tctsto_compare

	ADRL		r0, oct
	MOV		r2, #10
	BL		tctsto_compare

	ADRL		r0, nov
	MOV		r2, #11
	BL		tctsto_compare

	ADRL		r0, dec
	MOV		r2, #12
	BL		tctsto_compare

	B		tctsto_bad_string

tctsto_found
	STR		r2, [r3, #20]		; month

	MOV		r0, #10
	SWI		XOS_ReadUnsigned	; 1-448
	LDMVSFD		r13!, {r1-r7, pc}
	STR		r2, [r3, #24]		; year

	ADD		r5, r1, #1

	TEQ		r4, #2
	LDMEQFD		r13!, {r1-r7, pc}^

tctsto_time					; drop through
	MOV		r0, #10

	MOV		r1, r5
	SWI		XOS_ReadUnsigned	; 1-448
	LDMVSFD		r13!, {r1-r7, pc}
	STR		r2, [r3, #12]		; hours

	ADD		r1, r5, #3
	SWI		XOS_ReadUnsigned	; 1-448
	LDMVSFD		r13!, {r1-r7, pc}
	STR		r2, [r3, #8]		; minutes

	ADD		r1, r5, #6
	SWI		XOS_ReadUnsigned	; 1-448
	LDMVSFD		r13!, {r1-r7, pc}
	STR		r2, [r3, #4]		; seconds

	MOV		r0, #0
	STR		r0, [r3, #0]		; centiseconds

	LDMFD		r13!, {r1-r7, pc}^

tctsto_compare
	MOV		r1, r5
tctsto_loop
	LDRB		r6, [r1], #1		; STRing
	LDRB		r7, [r0], #1		; month
	TEQ		r7, #0
	TEQEQ		r6, #"-"
	BEQ		tctsto_found
	TEQ		r6, r7
	MOVNE		pc, r14

	B		tctsto_loop

tctsto_bad_string
	ADRL		r0, bad_string
	LDMFD		r13!, {r1-r7, r14}
	ORRS		pc, r14, #&10000000

;

territory_convertordinalstotime		; 3-819
	STMFD		r13!, {r14}

	MOV		r0, #1			; cheat: pass to UK territory
	SWI		XTerritory_ConvertOrdinalsToTime
	LDMVSFD		r13!, {pc}

	LDMFD		r13!, {pc}^

;

territory_alphabet				; 3-821
	MOV		r0, #ALPHABET_NUMBER
	MOVS		pc, r14

;

territory_alphabetidentifier			; 3-822
	ADR		r0, alphabet
	MOVS		pc, r14

alphabet
	DCB		ALPHABET_NAME
	DCB		0
	ALIGN

;

territory_selectkeyboardhandler		; 3-823
	; not implemented
	MOVS		pc, r14

;

territory_writedirection			; 3-824
	MOV		r0, #WRITE_DIRECTION
	MOVS		pc, r14

;

territory_characterpropertytable		; 3-826
	ADRL		r0, propertytables
	CMP		r1, #10
	ADRGTL		r0, unknown_property
	ORRGTS		pc, r14, #&10000000
	ADD		r0, r0, r1, LSL #5
	MOVS		pc, r14

;

territory_lowercasetable			; 3-828
	ADRL		r0, lowercasetable
	MOVS		pc, r14

;

territory_uppercasetable			; 3-829
	ADRL		r0, uppercasetable
	MOVS		pc, r14

;

territory_controltable				; 3-830
	ADRL		r0, controltable
	MOVS		pc, r14

;

territory_plaintable				; 3-831
	ADRL		r0, plaintable
	MOVS		pc, r14

;

territory_valuetable				; 3-832
	ADRL		r0, valuetable
	MOVS		pc, r14

;

territory_representationtable			; 3-833
	ADRL		r0, representationtable
	MOVS		pc, r14

;

territory_collate				; 3-834
	STMFD		r13!, {r1-r8, r14}

	ADRL		r6, lowercasetable
	ADRL		r7, plaintable
	ADRL		r8, collatetable

tc_loop
	LDRB		r4, [r1], #1
	LDRB		r5, [r2], #1

	CMP		r4, #32			; check for termination
	CMPLT		r5, #32
	MOVLT		r0, #0			; both end
	BLT		tc_end
	CMP		r4, #32
	MOVLT		r0, #-1			; 1 ends
	BLT		tc_end
	CMP		r5, #32
	MOVLT		r0, #1			; 2 ends
	BLT		tc_end

	TST		r3, #1			; ignore case
	LDRNEB		r4, [r6, r4]		; convert to lower case
	LDRNEB		r5, [r6, r5]

	TST		r3, #2			; ignore accents
	LDRNEB		r4, [r7, r4]		; convert to plain
	LDRNEB		r5, [r7, r5]

	LDRB		r4, [r8, r4]		; convert to sort priority
	LDRB		r5, [r8, r5]

	CMP		r4, r5			; do comparison
	BEQ		tc_loop

	MOVLT		r0, #-1
	MOVGT		r0, #1

tc_end
	CMP		r0, #0			; set flags

	LDMFD		r13!, {r1-r8, pc}	; no ^

;

territory_readsymbols				; 3-836
	TEQ		r1, #0			; STRings
	ADREQ		r0, trs_decimalpoint
	TEQ		r1, #1
	ADREQ		r0, trs_thousands
	TEQ		r1, #2
	ADREQ		r0, trs_digits
	TEQ		r1, #3
	ADREQ		r0, trs_intcurrency
	TEQ		r1, #4
	ADREQ		r0, trs_currency
	TEQ		r1, #5
	ADREQ		r0, trs_moneydecimalpoint
	TEQ		r1, #6
	ADREQ		r0, trs_moneythousands
	TEQ		r1, #7
	ADREQ		r0, trs_moneydigits
	TEQ		r1, #8
	ADREQ		r0, trs_moneypositive
	TEQ		r1, #9
	ADREQ		r0, trs_moneynegative
	TEQ		r1, #18
	ADREQ		r0, trs_listseparator

	TEQ		r1, #10			; values
	MOVEQ		r0, #SYMBOL_MONEYINTFRACTION
	TEQ		r1, #11
	MOVEQ		r0, #SYMBOL_MONEYFRACTION
	TEQ		r1, #12
	MOVEQ		r0, #SYMBOL_CURRENCYPLACE
	TEQ		r1, #13
	MOVEQ		r0, #SYMBOL_CURRENCYSPACE
	TEQ		r1, #14
	MOVEQ		r0, #SYMBOL_CURRENCYPLACENEG
	TEQ		r1, #15
	MOVEQ		r0, #SYMBOL_CURRENCYSPACENEG
	TEQ		r1, #16
	MOVEQ		r0, #SYMBOL_MONEYPOS
	TEQ		r1, #17
	MOVEQ		r0, #SYMBOL_MONEYNEG

	MOVS		pc, r14

trs_decimalpoint
	DCB		SYMBOL_DECIMALPOINT
	DCB		0
trs_thousands
	DCB		SYMBOL_THOUSANDS
	DCB		0
trs_digits
	DCD		SYMBOL_DIGITS
trs_intcurrency
	DCB		SYMBOL_INTCURRENCY
	DCB		0
trs_currency
	DCB		SYMBOL_CURRENCY
	DCB		0
trs_moneydecimalpoint
	DCB		SYMBOL_MONEYDECIMALPOINT
	DCB		0
trs_moneythousands
	DCB		SYMBOL_MONEYTHOUSANDS
	DCB		0
trs_moneydigits
	DCD		SYMBOL_MONEYDIGITS
trs_moneypositive
	DCB		SYMBOL_MONEYPOSITIVE
	DCB		0
trs_moneynegative
	DCB		SYMBOL_MONEYNEGATIVE
	DCB		0
trs_listseparator
	DCB		SYMBOL_LISTSEPARATOR
	DCB		0
	ALIGN

;

territory_readcalendarinformation		; 3-839
	STMFD		r13!, {r0-r2, r14}

	MOV		r0, #1			; pass to UK territory to get time
	SWI		XTerritory_ReadCalendarInformation
	ADDVS		r13, r13, #4
	LDMVSFD		r13!, {r1-r2, pc}

	MOV		r0, #CALENDAR_FIRSTWORKDAY
	STR		r0, [r2, #0]
	MOV		r0, #CALENDAR_LASTWORKDAY
	STR		r0, [r2, #4]
	MOV		r0, #CALENDAR_MAXLENAMPM
	STR		r0, [r2, #16]
	MOV		r0, #CALENDAR_MAXLENWE
	STR		r0, [r2, #20]
	MOV		r0, #CALENDAR_MAXLENW3
	STR		r0, [r2, #24]
	MOV		r0, #CALENDAR_MAXLENDY
	STR		r0, [r2, #28]
	MOV		r0, #CALENDAR_MAXLENST
	STR		r0, [r2, #32]
	MOV		r0, #CALENDAR_MAXLENMO
	STR		r0, [r2, #36]
	MOV		r0, #CALENDAR_MAXLENM3
	STR		r0, [r2, #40]
	MOV		r0, #CALENDAR_MAXLENTZ
	STR		r0, [r2, #44]

	LDMFD		r13!, {r0-r2, pc}^

;

territory_nametonumber				; 3-841
	STMFD		r13!, {r14}

	MOV		r0, #1			; pass to UK territory
	SWI		XTerritory_NameToNumber
	LDMVSFD		r13!, {pc}

	LDMFD		r13!, {pc}^

;

territory_transformstring			; 3-842
	STMFD		r13!, {r1-r5, r14}

	MOV		r0, #0			; find string length
tts_loop
	LDRB		r4, [r2, r0]
	ADD		r0, r0, #1
	CMP		r4, #32
	BGE		tts_loop

	SUB		r0, r0, #1

	CMP		r0, r3			; buffer too short so exit
	LDMGEFD		r13!, {r1-r5, pc}^

	ADRL		r5, collatetable

tts_loop2
	LDRB		r4, [r2], #1
	CMP		r4, #32
	BLT		tts_end
	LDRB		r4, [r5, r4]
	STRB		r4, [r1], #1
	B		tts_loop2

tts_end
	MOV		r4, #0
	STRB		r4, [r1]

	LDMFD		r13!, {r1-r5, pc}^

;

territory_reserved
	ADR		r0, unknown_SWI
	ORRS		pc, r14, #&10000000

;
; Division algorithm
;

; On entry
;     r0 = value
;     r1 = divisor
; On exit
;     r0 = value  divisor
;     f0, f1 corrupted

divide
	STMFD		r13!, {r14}

	FLTS		f0, r0			; just use the FP :-)
	FLTS		f1, r1
	FDVS		f0, f0, f1
	FIXM		r0, f0

	LDMFD		r13!, {pc}^

;
; Error Blocks
;

unknown_SWI
	DCD		&43040
	DCB		"Unknown Territory SWI"
	DCB		0
	ALIGN

unknown_property
	DCD		&43041
	DCB		"Unknown character property"
	DCB		0
	ALIGN

buffer_overflow
	DCD		&2C1
	DCB		"Buffer overflow"
	DCB		0
	ALIGN

unknown_field
	DCD		&2C2
	DCB		"Unknown '%' field"
	DCB		0
	ALIGN

unknown_format
	DCD		&2C3
	DCB		"Unknown format type"
	DCB		0
	ALIGN

bad_string
	DCD		&2C4
	DCB		"Bad time string"
	DCB		0

;
; Data
;

data
		^	data
propertytables	#	352
lowercasetable	#	256
uppercasetable	#	256
controltable	#	256
plaintable	#	256
valuetable	#	256
representationtable	#	16
collatetable	#	256

	ALIGN

;

	END
