NEW
PREFIX
AUTO 4,1
*--------------------------------------
* https://www.cise.ufl.edu/~cop4600/cgi-bin/lxr/http/source.cgi/lib/ansi/gmtime.c
*--------------------------------------
SECSDAY			.EQ 86400				60*60*24
CENTURY0		.EQ 19
YEAR0			.EQ 70
DAY0			.EQ 4					day 0 was a thursday
*--------------------------------------
				.DUMMY
				.OR ZPTMP
TIME.DWORD		.BS 4
TIME.DivDay		.BS 2
TIME.ModDay		.BS 3
TIME.Div60		.BS 2
TIME.Mod		.BS 1
TIME.Div3600	.BS 1
TIME.Century	.BS 1
TIME.Year		.BS 1
				.ED
*/--------------------------------------
* # Time
* Get System Time in Buffer
* ## C
* `time_t time (S.TIME* timer);`
* ## ASM
* `>LDYA timer`
* `>SYSCALL time`
* ## RETURN VALUE
* S.TIME filled with System date/time
*\--------------------------------------
K.Time			>STYA ZPPtr2
				>MLICALL MLIGETTIME
				>LDYAI DATELO
				>STYA ZPPtr1
				bra TIME.PTime2TimeP1P2
*/--------------------------------------
* # PTime2Time
*  Convert ProDOS Time To S.TIME
* ## C
* `int PTime2Time (long* ptime, S.TIME* timer);`
* ## ASM
* `>PUSHW timer`
* `>LDYA ptime`
* `>SYSCALL PTime2Time`
* ## RETURN VALUE
*\--------------------------------------
K.PTime2Time	jsr MEM.SPtr1PPtr2
TIME.PTime2TimeP1P2				
				ldy #1
				lda (ZPPtr1),y			Get Year
				lsr						C is high bit of month
				ldy #S.Time.YEAR
				sta (ZPPtr2),y			set year
				sta TIME.Year			for conputing Century/WDAY later
				
				lda (ZPPtr1)			Get Month/day
				pha						save Day
				ror
				lsr
				lsr
				lsr
				lsr
				ldy #S.Time.MONTH
				sta (ZPPtr2),y			set month
				
				pla						get back day
				and #$1F
				iny
				sta (ZPPtr2),y			set day
				
				lda TIME.Year			get back year
				
				cmp #69					if before 70 CC,if > 70, CS
				lda #0
				rol						get back C in bit 0
				eor #1					toggle C
				adc #19					set date before 1970 -> 20xx
				sta (ZPPtr2)			set Century
				sta TIME.Century		for conputing WDAY later

				ldy #2
				lda (ZPPtr1),y			Get Min
				tax
				iny
				lda (ZPPtr1),y			Get Hour
				
				ldy #S.Time.HOUR
				sta (ZPPtr2),y			set hour
				iny
				txa
				sta (ZPPtr2),y			set min
				iny
				lda #0
				sta (ZPPtr2),y			set seconds (ProDOS does not provide it)

* 1/1/1970 was Thursday...if not leap, add one, if leap add 2
		
K.ComputeWDAY	lda #3					Thursday : 4 (-1 for mod 7)
				pha
				lda #19
				sta TIME.DWORD
				lda #70
				sta TIME.DWORD+1
				
.1				ldy TIME.DWORD
				lda TIME.DWORD+1
				
				cpy TIME.Century
				bne .2
				cmp TIME.Year
				beq .4
				
.2				jsr TIME.IsLeapYearYA	CS = Leap			
				
				pla
				adc #1
				cmp #7
				bcc .3
				sbc #7					MOD 7
				
.3				pha
				inc TIME.DWORD+1
				lda TIME.DWORD+1
				cmp #100
				bne .1
				lda #0
				sta TIME.DWORD+1
				inc TIME.DWORD
				bra .1
				
.4				ldy #S.Time.MONTH
				lda (ZPPtr2),y			get month
				tax
				
.5				lda K.StrFTime.MDAY-1,x	get day count in this month
				bne	.6					february ?
				
				ldy TIME.Century
				lda TIME.Year
				jsr TIME.IsLeapYearYA		CS = Leap			
				
.6				pla
				adc K.StrFTime.MDAY-1,x
				cmp #7
				bcc .7
				sbc #7
				
.7				pha
				dex
				bne .5
				
				pla
				
				ldy #S.Time.DAY
				adc (ZPPtr2),y			get day in month (1..31)
				dec						adjust range 0.30 for MOD 7
				
.8				cmp #7					MOD 7
				bcc .80
				sbc #7
				bra .8
				
.80				inc						adjust range 1..7				
				ldy #S.Time.WDAY
				sta (ZPPtr2),y
				
				clc
				rts
*/--------------------------------------
* # CTime2Time
*  Convert CTime Time To S.TIME
* ## C
* `int CTime2Time (long* ctime, S.TIME* timer);`
* ## ASM
* `>PUSHW timer`
* `>LDYA ctime`
* `>SYSCALL CTime2Time`
* ## RETURN VALUE
*\--------------------------------------
K.CTime2Time	jsr MEM.SPtr1PPtr2
				
				ldy #3
				
.1				lda (ZPPtr1),y
				sta TIME.DWORD,y
				dey
				bpl .1
				
				stz	TIME.DivDay
				stz	TIME.DivDay+1
				
.2				lda TIME.DWORD		
				sta TIME.ModDay
				sec
				sbc #SECSDAY
				pha
				
				lda TIME.DWORD+1
				sta TIME.ModDay+1
				sbc /SECSDAY
				pha
				
				lda TIME.DWORD+2
				sta TIME.ModDay+2
				sbc ^SECSDAY
				pha

				lda TIME.DWORD+3
				sbc #0
				bcc .3					end of DIV/MOD ?
				
				sta TIME.DWORD+3

				ldx #2
				
.21				pla
				sta TIME.DWORD,x
				dex
				bpl .21
				
				inc TIME.DivDay
				bne .2
				inc TIME.DivDay+1
				bne .2
				
.3				pla
				pla
				pla
				stz TIME.Div60
				stz TIME.Div60+1

.4				lda TIME.ModDay
				sta TIME.Mod
				sec
				sbc #60
				pha
				
				lda TIME.ModDay+1
				sbc #0
				pha
				
				lda TIME.ModDay+2
				sbc #0
				
				bcc .5
				
				sta TIME.ModDay+2
				pla
				sta TIME.ModDay+1
				pla
				sta TIME.ModDay

				inc TIME.Div60
				bne .4
				inc TIME.Div60+1
				bne .4
				
.5				pla
				pla
				lda TIME.Mod
				ldy #S.Time.SECOND
				sta (ZPPtr2),y
				
				stz TIME.Div3600
				
.6				lda TIME.Div60				
				sta TIME.Mod
				sec
				sbc #60
				pha
				
				lda TIME.Div60+1
				sbc #0
				pha

				bcc .7
				
				sta TIME.Div60+1
				pla
				sta TIME.Div60
				
				inc TIME.Div3600
				bne .6
				
.7				pla

				lda TIME.Mod
				dey						ldy #S.Time.MINUTE
				sta (ZPPtr2),y
				
				lda TIME.Div3600
				dey						ldy #S.Time.HOUR
				sta (ZPPtr2),y
				
				lda TIME.DivDay		WDAY computation : (DivDay + DAY0) mod 7
				clc
				adc #DAY0
				pha
				lda TIME.DivDay+1
				adc /DAY0
				eor #$ff
				tax
				pla
				
.8				sta TIME.Mod
				sec
				sbc #7
				bcs .8
				inx
				bne .8
				
				lda TIME.Mod
				ldy #S.Time.WDAY
				sta (ZPPtr2),y
				
				lda #CENTURY0
				sta TIME.Century
				lda #YEAR0
				sta TIME.Year

K.CTime2Time.Year				
.1				ldy TIME.Century
				lda TIME.Year
				jsr TIME.IsLeapYearYA 		if Leap year CS
				
				lda #0						Toggle Carry
				rol
				eor #1
				lsr
				
				lda TIME.DivDay
				sbc #365
				pha
				lda TIME.DivDay+1
				sbc /365
				bcc .2
				
				sta TIME.DivDay+1
				pla
				sta TIME.DivDay
				
				inc TIME.Year
				lda TIME.Year
				cmp #100
				bne .1
				stz TIME.Year
				inc TIME.Century
				bne .1
				
.2				pla
				lda TIME.Century
*				ldy #S.Time.CENTURY
				sta (ZPPtr2)
				ldy #S.Time.YEAR
				lda TIME.Year
				sta (ZPPtr2),y
				
				clc
				rts
*--------------------------------------
* In :
*  Y = Century
*  A = Year (0..99)
*    if (year mod 400 = 0)
*      or 
*    if  not (year mod 100 = 0) and (year mod 4 = 0)
* Out :
*  CS = Leap
*  CC = Not Leap
*--------------------------------------
TIME.IsLeapYearYA
				cmp #0					Year = 00 ?
				bne .1					no
				
				tya						year = 00, get century in a
				and #$3					mod 4 = 0 ?
				beq .9					leap year
				
.8				clc						not leap
				rts

.1				and #$3					mod 4 = 0 ?
				bne .8
				
.9				sec						Leap
				rts
*--------------------------------------
K.StrFTime.MDAY	.DA #3,#0,#3,#2,#3,#2,#3,#3,#2,#3,#2,#3
*/--------------------------------------
* # StrFTime
* ## C
* Convert S.TIME struct to CSTR
* `void strftime (char* ptr, const char* format, const struct S.TIME* timeptr );`
* ## ASM
* `PUSHW timeptr`
* `PUSHW format`
* + %a : Abbreviated weekday name : Thu
* + %A : Full weekday name : Thursday 
* + %b : Abbreviated month name : Aug 
* + %B : Full month name : August 
* + %d : Day of the month, zero-padded (01-31)
* + %H : Hour in 24h format (00-23) 14 
* + %I : Hour in 12h format (01-12) 02 
* + %m : Month as a decimal number (01-12) 08 
* + %M : Minute (00-59) 55 
* + %p : AM or PM designation PM 
* + %S : Second (00-61) 02 
* + %w : Weekday as a decimal number with Sunday as 0 (0-6) 
* + %y : Year, last two digits (00-99)
* + %Y : Year four digits 2001 
* `>LDYA ptr`
* `>SYSCALL strftime`
* ## RETURN VALUE
*   none. always succeed.
*\--------------------------------------
K.StrFTime		jsr MEM.SPtr1PPtr2
				>PULLW ZPPtr3			timeptr
				
.1				lda (ZPPtr2)
				beq .8
				
				jsr MEM.NextCharPtr2
				
				cmp #'%'
				beq .2
				
				jsr K.StrFTime.addChar
				bra .1
				
.2				ldx #K.StrFTime.JMP-K.StrFTime.Tbl-1
				
				lda (ZPPtr2)
				beq .8
				
				jsr MEM.NextCharPtr2
				
.3				cmp K.StrFTime.Tbl,x
				beq .4
				dex
				bpl .3
				bra .1
				
.4				txa
				asl
				tax
				jsr .5
				bra .1

.5				jmp (K.StrFTime.JMP,x)			

.8				lda #0					Terminate C string
				sta (ZPPtr1)
				clc
				rts
*--------------------------------------
K.StrFTime.TBL	.AS "aAbBdHImMpSwyY"
K.StrFTime.JMP	.DA K.StrFTime.A
				.DA K.StrFTime.AA
				.DA K.StrFTime.B
				.DA K.StrFTime.BB
				.DA K.StrFTime.D
				.DA K.StrFTime.HH
				.DA K.StrFTime.II
				.DA K.StrFTime.M
				.DA K.StrFTime.MM
				.DA K.StrFTime.P
				.DA K.StrFTime.SS
				.DA K.StrFTime.W
				.DA K.StrFTime.Y
				.DA K.StrFTime.YY
*--------------------------------------
K.StrFTime.A	ldx #3					Short day of week, 3 chars...
				.HS	2C					Bit abs				
				 
K.StrFTime.AA	ldx #15					full DoW
				>LDYAI K.StrFTime.DAY
				>STYA ZPPtr4		
				ldy #S.Time.WDAY
				bra K.StrFTime.STR
				
K.StrFTime.B	ldx #3					Short Month, 3 chars....
				.HS	2C					Bit abs
				
K.StrFTime.BB	ldx #15					full Month....
				>LDYAI K.StrFTime.MON
				>STYA ZPPtr4		
				ldy #S.Time.MONTH
				
K.StrFTime.STR	lda (ZPPtr3),y 			get required S.Time field value
				tay
				beq .9					Illegal value
				
.1				dey						range 0..x
				beq .2
				lda (ZPPtr4)
				sec
				adc ZPPtr4
				sta ZPPtr4
				bcc .1
				inc ZPPtr4+1
				bra .1
				
.2
*				ldy #0					Y is already 0

.3				iny
				lda (ZPPtr4),y
				jsr K.StrFTime.addChar
				tya
				cmp (ZPPtr4)
				beq .8
				
				dex
				bne .3
.8				rts
				
.9				ldx #3
				lda #'?'
.99				jsr K.StrFTime.addChar
				dex
				bne .99
				rts
*--------------------------------------
K.StrFTime.II	ldy #S.Time.HOUR
				lda (ZPPtr3),y
				cmp #12
				bcc .1
				sbc #12
.1				bra K.StrFTime.addDecA
K.StrFTime.P	ldy #S.Time.HOUR
				lda (ZPPtr3),y
				cmp #12
				bcc .1
				lda #'p'
				.HS 2C					bit abs
.1				lda #'a'
				jsr K.StrFTime.addChar
				lda #'m'
				bra K.StrFTime.addChar
K.StrFTime.YY	ldy #S.Time.CENTURY
				jsr K.StrFTime.addDecPtr1Y
K.StrFTime.Y	ldy #S.Time.YEAR
				.HS 2C					bit abs
K.StrFTime.D	ldy #S.Time.DAY
				.HS 2C					bit abs
K.StrFTime.HH	ldy #S.Time.HOUR
				.HS 2C					bit abs
K.StrFTime.SS	ldy #S.Time.SECOND
				.HS 2C					bit abs
K.StrFTime.W	ldy #S.Time.WDAY
				.HS 2C					bit abs
K.StrFTime.M	ldy #S.Time.MONTH
				.HS 2C					bit abs
K.StrFTime.MM	ldy #S.Time.MINUTE
*--------------------------------------
K.StrFTime.addDecPtr1Y
				lda (ZPPtr3),y
K.StrFTime.addDecA
				
				stz .2+1
				
				ldx #8
				sed
				
.1				asl
				pha
.2				lda #$ff				Self Modified

				adc .2+1
				sta .2+1
				
				pla
				dex
				bne .1
				
				cld

				lda .2+1
				pha
				lsr
				lsr
				lsr
				lsr
				ora #$30
				jsr K.StrFTime.addChar
				pla
				and #$0f
				ora #$30
*--------------------------------------
K.StrFTime.addChar
				sta (ZPPtr1)
				jmp MEM.NextCharPtr1
*--------------------------------------
K.StrFTime.DAY	>PSTR "Monday"
				>PSTR "Tuesday"
				>PSTR "Wednesday"
				>PSTR "Thursday"
				>PSTR "Friday"
				>PSTR "Saturday"
				>PSTR "Sunday"
*--------------------------------------
K.StrFTime.MON	>PSTR "January"
				>PSTR "February"
				>PSTR "March"
				>PSTR "April"
				>PSTR "May"
				>PSTR "June"
				>PSTR "July"
				>PSTR "August"
				>PSTR "September"
				>PSTR "October"
				>PSTR "November"
				>PSTR "December"
*--------------------------------------
MAN
SAVE USR/SRC/SYS/KERNEL.S.TIME
LOAD USR/SRC/SYS/KERNEL.S
ASM
