CCCPaste

VAX/VMS Macro-32 TERVEHDYS.MAR

.TITLE TERVEHDYS
.IDENT /V1.4/

.LIBRARY /SYS$LIBRARY:STARLET.MLB/

$SSDEF
$DSCDEF

.PSECT DATA,NOEXE,WRT,LONG

UTC_TIME: .BLKQ 1
UTCNUM: .BLKW 7
FINNUM: .BLKW 7

DAY: .BLKL 1
YEAR: .BLKL 1
HOUR: .BLKL 1
MINUTE: .BLKL 1
SECOND: .BLKL 1

MAR_LAST: .BLKL 1
OCT_LAST: .BLKL 1
MONTH_PTR: .BLKL 1
OFFSET_HOURS: .BLKL 1
MONTH_LEN: .BLKL 1

OUTBUF: .BLKB 132
OUTLEN: .BLKW 1

OUT_DSC:
.WORD 132
.BYTE DSC$K_DTYPE_T
.BYTE DSC$K_CLASS_S
.ADDRESS OUTBUF

FMT_DATE: .ASCID /!UL. !AS !UL !2ZL:!2ZL:!2ZL Suomen aikaa/

MON01: .ASCID /tammikuuta/
MON02: .ASCID /helmikuuta/
MON03: .ASCID /maaliskuuta/
MON04: .ASCID /huhtikuuta/
MON05: .ASCID /toukokuuta/
MON06: .ASCID /kesakuuta/
MON07: .ASCID /heinakuuta/
MON08: .ASCID /elokuuta/
MON09: .ASCID /syyskuuta/
MON10: .ASCID /lokakuuta/
MON11: .ASCID /marraskuuta/
MON12: .ASCID /joulukuuta/

MONTH_TABLE:
.ADDRESS MON01,MON02,MON03,MON04,MON05,MON06
.ADDRESS MON07,MON08,MON09,MON10,MON11,MON12

MDAYS:
.LONG 31,28,31,30,31,30,31,31,30,31,30,31

MSG_TIME: .ASCID /Paivamaara ja aika:/
GREET_MORN: .ASCID /Hyvaa huomenta!/
GREET_DAY: .ASCID /Hyvaa paivaa!/
GREET_EVE: .ASCID /Hyvaa iltaa!/
GREET_NIGHT: .ASCID /Hyvaa yota!/

.PSECT CODE,EXE,NOWRT,LONG

.ENTRY START,^M<>

$GETTIM_S TIMADR=UTC_TIME
BLBS R0,10$
JMP ERROR
10$:
$NUMTIM_S TIMBUF=UTCNUM,TIMADR=UTC_TIME
BLBS R0,20$
JMP ERROR
20$:

; Find last Sunday of March and October in the UTC year.
MOVZWL UTCNUM+0,R0
MOVL #3,R1
MOVL #31,R2
BSBW LAST_SUNDAY
MOVL R0,MAR_LAST

MOVZWL UTCNUM+0,R0
MOVL #10,R1
MOVL #31,R2
BSBW LAST_SUNDAY
MOVL R0,OCT_LAST

; Default: Finnish winter time, UTC+2.
MOVL #2,OFFSET_HOURS

; Finnish summer time: last Sunday of March 01:00 UTC
; through last Sunday of October before 01:00 UTC.
MOVZWL UTCNUM+2,R0 ; UTC month

CMPL R0,#3
BLSS HAVE_OFFSET ; Jan-Feb

CMPL R0,#10
BGTR HAVE_OFFSET ; Nov-Dec

CMPL R0,#3
BEQL CHECK_MARCH

CMPL R0,#10
BEQL CHECK_OCTOBER

MOVL #3,OFFSET_HOURS ; Apr-Sep
BRW HAVE_OFFSET

CHECK_MARCH:
MOVZWL UTCNUM+4,R0 ; UTC day
CMPL R0,MAR_LAST
BLSS HAVE_OFFSET
BGTR MARCH_DST

MOVZWL UTCNUM+6,R0 ; UTC hour
CMPL R0,#1
BLSS HAVE_OFFSET

MARCH_DST:
MOVL #3,OFFSET_HOURS
BRW HAVE_OFFSET

CHECK_OCTOBER:
MOVL #3,OFFSET_HOURS ; October is DST until cutoff
MOVZWL UTCNUM+4,R0
CMPL R0,OCT_LAST
BLSS HAVE_OFFSET
BGTR OCT_STD

MOVZWL UTCNUM+6,R0
CMPL R0,#1
BLSS HAVE_OFFSET

OCT_STD:
MOVL #2,OFFSET_HOURS

HAVE_OFFSET:
; Copy UTC numeric time to FINNUM.
MOVW UTCNUM+0,FINNUM+0
MOVW UTCNUM+2,FINNUM+2
MOVW UTCNUM+4,FINNUM+4
MOVW UTCNUM+6,FINNUM+6
MOVW UTCNUM+8,FINNUM+8
MOVW UTCNUM+10,FINNUM+10
MOVW UTCNUM+12,FINNUM+12

; Add 2 or 3 hours.
MOVZWL FINNUM+6,R0
ADDL2 OFFSET_HOURS,R0
CMPL R0,#24
BLSS STORE_HOUR

SUBL2 #24,R0
MOVW R0,FINNUM+6
BSBW INC_DATE
BRW AFTER_HOUR

STORE_HOUR:
MOVW R0,FINNUM+6

AFTER_HOUR:
MOVZWL FINNUM+0,YEAR
MOVZWL FINNUM+4,DAY
MOVZWL FINNUM+6,HOUR
MOVZWL FINNUM+8,MINUTE
MOVZWL FINNUM+10,SECOND

MOVZWL FINNUM+2,R1
DECL R1
MULL2 #4,R1
MOVL MONTH_TABLE(R1),MONTH_PTR

PUSHL SECOND
PUSHL MINUTE
PUSHL HOUR
PUSHL YEAR
PUSHL MONTH_PTR
PUSHL DAY
PUSHAQ OUT_DSC
PUSHAL OUTLEN
PUSHAQ FMT_DATE
CALLS #9,G^LIB$SYS_FAO
BLBS R0,30$
JMP ERROR
30$:
MOVW OUTLEN,OUT_DSC

PUSHAQ MSG_TIME
CALLS #1,G^LIB$PUT_OUTPUT

PUSHAQ OUT_DSC
CALLS #1,G^LIB$PUT_OUTPUT

CMPW FINNUM+6,#6
BLSS SAY_NIGHT

CMPW FINNUM+6,#12
BLSS SAY_MORN

CMPW FINNUM+6,#18
BLSS SAY_DAY

CMPW FINNUM+6,#22
BLSS SAY_EVE

SAY_NIGHT:
PUSHAQ GREET_NIGHT
BRB PRINT_GREET

SAY_MORN:
PUSHAQ GREET_MORN
BRB PRINT_GREET

SAY_DAY:
PUSHAQ GREET_DAY
BRB PRINT_GREET

SAY_EVE:
PUSHAQ GREET_EVE

PRINT_GREET:
CALLS #1,G^LIB$PUT_OUTPUT
MOVL #SS$_NORMAL,R0
RET

ERROR:
PUSHL R0
CALLS #1,G^LIB$STOP
RET

; Increment FINNUM date by one day.

INC_DATE:
MOVZWL FINNUM+0,R0 ; year
MOVZWL FINNUM+2,R1 ; month
BSBW GET_MONTH_LENGTH
MOVL R0,MONTH_LEN

MOVZWL FINNUM+4,R0 ; day
INCL R0
CMPL R0,MONTH_LEN
BGTR NEXT_MONTH

MOVW R0,FINNUM+4
RSB

NEXT_MONTH:
MOVW #1,FINNUM+4

MOVZWL FINNUM+2,R0
INCL R0
CMPL R0,#12
BGTR NEXT_YEAR

MOVW R0,FINNUM+2
RSB

NEXT_YEAR:
MOVW #1,FINNUM+2
MOVZWL FINNUM+0,R0
INCL R0
MOVW R0,FINNUM+0
RSB

; Input:
; R0 = year
; R1 = month
; Output:
; R0 = length of month

GET_MONTH_LENGTH:
DECL R1
MULL2 #4,R1
MOVL MDAYS(R1),R2

; February: check leap year.
CMPL R1,#4 ; original month 2 -> index 1 -> offset 4
BNEQ MONTH_LEN_DONE

BSBW IS_LEAP
TSTL R0
BEQL MONTH_LEN_DONE
MOVL #29,R2

MONTH_LEN_DONE:
MOVL R2,R0
RSB

; Input:
; R0 = year
; Output:
; R0 = 1 if leap year, 0 otherwise

IS_LEAP:
MOVL R0,R3

MOVL R3,R4
DIVL2 #400,R4
MULL2 #400,R4
CMPL R3,R4
BEQL LEAP_YES

MOVL R3,R4
DIVL2 #100,R4
MULL2 #100,R4
CMPL R3,R4
BEQL LEAP_NO

MOVL R3,R4
DIVL2 #4,R4
MULL2 #4,R4
CMPL R3,R4
BEQL LEAP_YES

LEAP_NO:
CLRL R0
RSB

LEAP_YES:
MOVL #1,R0
RSB

; Input:
; R0 = year
; R1 = month, 3 or 10
; R2 = last day of month
; Output:
; R0 = day number of last Sunday in that month

LAST_SUNDAY:
MOVL R0,R3
MOVL R1,R4
MOVL R2,R5

ADDL3 #1,R4,R6
MULL2 #13,R6
DIVL2 #5,R6

ADDL3 R5,R6,R7
ADDL2 R3,R7

MOVL R3,R8
DIVL2 #4,R8
ADDL2 R8,R7

MOVL R3,R8
DIVL2 #100,R8
SUBL2 R8,R7

MOVL R3,R8
DIVL2 #400,R8
ADDL2 R8,R7

MOVL R7,R8
DIVL2 #7,R8
MULL2 #7,R8
SUBL2 R8,R7

ADDL2 #6,R7
MOVL R7,R8
DIVL2 #7,R8
MULL2 #7,R8
SUBL2 R8,R7

SUBL3 R7,R5,R0
RSB

.END START