;       DATE.SBR
;       VER 1.0         8608.12
;       
;
;
;       PROPRIETARY PROGRAM MATERIAL
;
;       THIS MATERIAL IS THE PROPERTY OF JEFF STUYVESANT,
;       12307 PACIFIC AVE, APT 2,MAR VISTA, CALIF. ,90066
;       PERMISSION TO COPY AND USE IS GRANTED FOR 
;       NON-PROFIT USES ONLY.
;
;       Copyright (c) 1986 JEFF STUYVESANT


        SEARCH  SYS
        SEARCH  SYSSYM
        SEARCH  TRM

        OBJNAM  DATE.SBR

        RADIX 8.
        
VMAJOR  =       1.
VMINOR  =       0.
VSUB    =       0.
VEDIT   =       0.
VWHO    =       0.

;MACROS
DEFINE  GET.D   O.SET,DEST
        MOV     O.SET(A3),DEST
        ENDM

DEFINE  GET.I   O.SET,DEST
        MOV     O.SET(A3),DEST
        SWAP    DEST
        ENDM

DEFINE  SAV.D   O.SET,SORC
        MOV     SORC,O.SET(A3)
        ENDM

DEFINE  SAV.I   O.SET,SORC
        SWAP    SORC
        MOV     SORC,O.SET(A3)
        ENDM

;EQUATES
;       DSECT
        A.SIZE  =       8.
        A.ADDR  =       4.

        V.DATE  =       0.
        V.INTL  =       0.
        V.BASE  =       4.
        V.MODE  =       8.      
        V.LEAP  =       8.      

;       PSECT
        PHDR    -1,0,PH$REE!PH$REU

START:          ; A3 POINTS TO BASE OF ARG LIST
                CMPW    @A3,#1                  ; ONLY ONE ARG
                JNE     SBR.ERROR
                CMP     A.SIZE(A3),#10.         ; 10 BYTES IN SIZE
                JLO     SBR.ERROR
                MOV     A.ADDR(A3),A3           ; GET ADDR OF VARIBLE
                MOVW    V.MODE(A3),D5           ; MOV MODE INTO D5
                BEQ     SBR.ERROR               ; ERROR IF ZERO
                CMPW    D5,#5.                  ; IS IT MODE 5
                JEQ     MODE.5                  ; BR TRUE
                BHI     SBR.ERROR               ; ERROR IF GREATER
        ; PROCESS MODE 1 TO 4

                GET.D   V.DATE,D6               ; GET DATE'SEP
                BEQ     DATE.ERROR              ; CANT BE ZERO
                CALL    $DTO.I                  ; CALC DATE TO INTERNAL
                BEQ     DATE.ERROR              ; INVALID DATE IF Z FLAG
                MOVW    D7,V.LEAP(A3)           ; SAVE LEAP'YEAR FLAG

                CMPW    D5,#4.                  ; IS IT MODE 4?
                BEQ     MODE.4                  ; BR IF YES

        ; DATE ENTERED AS INTERNAL IN D6
                MOV     D6,D3
                CALL    DOW                     ; CALC DAY OF WEEK SAVE IN D3
                CMPW    D5,#2.
                BLO     EXIT                    ; LOW IS ONLY MODE 1
                BEQ     MODE.2                  ; BR IF = MODE 2
                                                ; MUST BE MODE 3
MODE.3:         ; SECOND DATE IN DATE'BASE
                TST     V.BASE(A3)              ; BASE CANT=0
                BEQ     DATE.ERROR              ; BR IF =
                SAV.I   V.INTL,D6               ; SAVE DATE AS DAYS
                GET.D   V.BASE,D6               ; GET DATE'BASE(AS DATE)
                BEQ     DATE.ERROR              ; CANT BE ZERO
                CALL    $DTO.I                  ; CALC DATE TO INTERNAL
                BEQ     DATE.ERROR              ; INVALID DATE IF Z FLAG
                GET.I   V.INTL,D7               ; GET DATE'SEP(AS'DAYS)
                XCH     D6,D7                   ; SET INTO PROPER ORDER
        ; D6= DATE(AS DAYS [LARGER])
        ; D7= DATE'BASE(AS DAYS [SMALLER])

SUB.01:         CMP     D7,D6                   ; COMPARE THE TWO DATES(AS DAYS)
                BHI     DATE.ERROR              ; BR IF BASE > SEP.
                SUB     D7,D6                   ; SEP-BASE= DIFFERENCE

; END OF PROGRAM
EXIT:           SAV.I   V.INTL,D6               ; SAVE DAYS
EXIT$:          SAV.I   V.BASE,D3               ; SAVE DOW
                RTN

;MODE OR ARG IN ERROR
SBR.ERROR:      MOV     #0,V.INTL(A3)           ; USED WHEN PARAMETERS
                MOV     #0,V.BASE(A3)           ; ARE IN ERROR
                SETW    V.MODE(A3)              ; MODE/#OF ARG ETC.
                RTN

; DATA IN ERROR
DATE.ERROR:     SET     V.INTL(A3)              ; USED WHEN VARIBLES ARE
                SET     V.BASE(A3)              ; IN ERROR
                SETW    V.MODE(A3)              ; DATE NOT DATE/ ETC
                RTN

MODE.2: ; D6=DATE(AS DAYS)
        ; SUB DATE'BASE(AS DAYS) AND FINISH

                GET.I   V.BASE,D7               ; GET DATE'BASE(AS DAYS)

                ; D7= DATE(AS DAYS [LARGER])
                ; D6= DATE'BASE(AS DAYS [SMALLER])

                BR      SUB.01                  ; SUB AND SAVE

MODE.4: ; D6=DATE(AS DAYS)
        ; ADD DATE'BASE(AS DAYS) SEND BACK
        ;       DATE'INTERNAL

                GET.I   V.BASE,D7               ; GET DATE'BASE(AS DATE)
                ADD     D7,D6                   ; CALC NEW DAYS
                MOV     D6,D4                   ; CALL USES D4
                BR      CALC.INTL               ; CALC NEW DATE
MODE.5:
        ; GET D4 AS DAYS
        ; RETURN DATE
                MOVW    #0,V.MODE(A3)           ; CLEAR MODE
                GET.I   V.DATE,D4               ; GET DATE(AS DAYS)
                BEQ     DATE.ERROR              ; BR IF = 0
CALC.INTL:      
                MOV     D4,D3                   ; SET UP FOR DOW
                CALL    DOW                     ; CALC DAY OF WEEK
                CALL    $ITO.D                  ; CONVERT TO DATE
                BEQ     DATE.ERROR              ; DAYS IN ERROR
                SAV.D   V.DATE,D6               ; SAVE IT AND FINISH
                BR      EXIT$

$ITO.D:         ; D4 CONTAINS DAYS TO BE CONVERTED
                SAVE    D0-D2,A5
                SUB     #2351425.,D4            ; CORRECT FROM AM FORMAT
                CMP     D4,#0.                  ; CMP TO 0
                JLOS    NO.GOOD                 ; NO GOOD IF 0 OR LESS
                MOV     #146097.,D6             ; SET DIVISOR INTO D6
                SUB     #12.,SP                 ; GRAB SOME WORKSPACE
                LEA     A6,(SP)                 ; A6 TO POINT TO IT
                FLTOF   D6,@A6                  ; CONVERT D6 TO FLOAT .
                ADD     #6.,A6                  ; POINT TO NEW LOCATION
                MOV     D4,D6                   ; GET DAYS TO CONVERT
                ADD     #364.,D6                ; CORRECTION OF 1 YR-1
                FLTOF   D6,@A6                  ; CNVT TO FLOAT .
                MOV     SP,A5                   ; SAVE SP
                FDIV    A5,A6                   ; DIV THE NUMBERS
                MOV     A6,A5                   ; GET BASE OF NUMBERS
                FFTOL   @A5,D6                  ; CNVT FROM FLOAT .->D6
                ADD     #12.,SP                 ; RESET SP
                INC     D6                      ; ADD ONE TO ANSWER
                MOV     D4,D0                   ; SAVE IT
                ADD     #364.,D0                ; ADD CORRECTION 1 YR-1
                SUB     D6,D0                   ; CALC DIFERENCE

                MOV     D0,D1                   ; SAVE IT
P2:     ; CALCULATION PART TWO
                DIV     D0,#36524.              ; DIVIDE D0
                AND     #177777,D0              ; ELIMINATE REMAINDER
                INC     D0                      ; ADD 1
                ADD     D0,D1                   ; ADD TO SAVED NUMBER
                MOV     D1,D0                   ; AND SAVE A COPY
P3:     ; CALCULATION PART THREE
                DIV     D0,#1461.               ; DIVIDE D0
                AND     #177777,D0              ; ELIMINATE REMAINDER
                SUB     D0,D1                   ; SUB FROM SAVED NUMBER
P4:     ; CALCULATION PART FOUR
                DIV     D1,#365.                ; DIVIDE BY DAYS IN YEAR
                AND     #177777,D1              ; ELIMINATE REMAINDER
        
        ; D1 = YEAR
        ;@SP = #OF DAYS ENTERED

                MOV     D1,D6                   ; SAVE YEAR
                CALL    CALC.D                  ; CALC # OF DAYS TO 01/00/YEAR
                MOV     D4,D1                   ; SAVE DAYS

        ; D0 = # OF DAYS FROM 01/01/01 TO 01/00/YEAR
        ; D1 = # OF DAYS FROM 01/01/01 TO MO/DAY/YEAR
        ; D4 =    "       "      "     "      "
        ; D6 = YEAR
        ; D7 = 1 FOR LEAP YEAR/ 0 IF NOT

                SUB     D0,D1                   ; CALC DAYS
        ; D1 = # OF DAYS FROM 01/00/YEAR TO MO/DAY/YEAR
        ; D6 = YEAR
        ; D7 = 1 FOR LEAP YEAR/ 0 IF NOT

; DETERMINE MO AND DAY
                MOVW    #1,D0                   ; SET MO POINTER
                CLR     D2                      ; PRE-CLEAR
        10$:    MOVB    EOM[~D0],D2             ; GET DAYS IN MONTH (D0)
                CMPW    D0,#2                   ; IS IF FEBUARY
                BNE     15$                     ; BR IF NOT
                ADDB    D7,D2                   ; YES ADD D7= LEAP YEAR

        15$:    CMPW    D1,D2                   ; CMP DAYS TO DATE TO EOM
                BLOS    20$                     ; IF LESS WE FOUND IT
                SUBW    D2,D1                   ; SUB DAYS IN MO FROM DAYS TO DATE
                INCW    D0                      ; INC MO POINTER
                BR      10$                     ; TRY AGAIN

                ; DATE FOUND PACKIT WITH YEAR
        20$:
        ; D0 = MONTH
        ; D1 = DAY
        ; D6 = YEAR
                LSLW    D1,#8.                  ; SHIFT LEFT EIGHT BITS
                MOVB    D0,D1                   ; SET LOWER BYTE =MO
        ; D1.W = MO/DAY
                MOV     #16.,D2                 ; SET COUNTER
                ROL     D6,D2                   ; ROLL LEFT 16 BITS
                MOVW    D1,D6                   ; SET LOW WORD=MO/DAY
                ROR     D6,D2                   ; ROLL RIGHT 16 BITS
                JMP     FIN                     ; ALL DONE
        ; D6 = MO/DAY/YEAR

        ; PROCESS ERRORS
NO.GOOD:        REST    D6                      ; RET REGISTERS
DATE.NO.GOOD:
                LCC     #PS.Z                   ; INDICATE ERROR
FIN:            REST    D0-D2,A5                ; REST REGISTERS
                RTN

        ; LIST OF DAYS IN MONTH
EOM:            BYTE    0,31.,28.,31.,30.,31.,30.,31.,31.,30.,31.,30.,31.
                EVEN

$DTO.I:         ; ENTER D6= DATE IN SEP FORMAT (NOT AM STANDARD)

                SAVE    D0-D2,A5                ; SAVE REGISTERS
                CMPW    D6,#10000.              ; YEAR MAX IS 10,000 DECIMAL
                BHI     DATE.NO.GOOD            ; BR IF NO GOOD

                CALL    CALC.D                  ; CALC DAYS TO 01/00/YEAR

        ; D0=NUMBER OF DAYS TO FIRST OF YEAR -1
        ; D7= LEAP YEAR 1=YES 0=NO

MO.VER:         ; VERIFY MONTH
                SWAP    D6                      ; GET MONTH IN LOWER BYTE
                CMPB    D6,#12.                 ; CHECK WITH 12 MONTHS
                BHI     DATE.NO.GOOD            ; IF HI NO GOOD

                ; CALC UP TO MONTH
                CLR     D2                      ; PRE-CLEAR
                MOV     #1,D1                   ; SET MONTH POINTER
        10$:    
                CMPB    D1,D6                   ; AT MONTH YET
                BEQ     DAY.VER                 ; BR IF YES
                MOVB    EOM[~D1],D2             ; NO GET DAYS IN MONTH PRIOR
                ADD     D2,D0                   ; ADD TO CUMULATIVE
                INCB    D1                      ; INC MO POINTER
                BR      10$                     ; BR AGAIN

DAY.VER:        ; VERIFY DAY GIVEN
                ROLW    D6,#8.                  ; ROLL WORD LEFT 8 BITS
                CMPB    D6,EOM[~D1]             ; CMP DAYS IN MO TO PASSED
                BHI     20$                     ; BR IF HI MAYBE NO GOOD
                MOVB    D6,D2                   ; SET D2=PASSED VALUE
                ADD     D2,D0                   ; ADDIT TO CUMLUATIVE
                CMPB    D7,#1                   ; LEAP YEAR ?
                BNE     10$                     ; BR IF NOT
                CMPB    D1,#2                   ; PAST FEBUARY
                BLOS    10$                     ; BR IF NOT
                ADD     #1,D0                   ; INC CUMULATIVE
        ; ALL DONE
        10$:
                BR      FINISH
        
        ; DAYS PAST MAY BE TOO HIGH
        20$:
                CMPB    D1,#2                   ; MO PASSED FEBUARY
                BNE     DATE.NO.GOOD            ; BR IF NOT
                CMPB    D7,#1                   ; THIS A LEAP YEAR
                BNE     DATE.NO.GOOD            ; BR IF NOT
                CMPB    D6,#29.                 ; ONLY #29 ALLOWED
                BNE     DATE.NO.GOOD            ; BR IF NOT
                ADD     #29.,D0                 ; INC D0 BY 29 DAYS
        ; ALL DONE
FINISH:         
                MOV     D0,D6                   ; RESET D6
                ADD     #2351425.,D6            ; CORRECT TO AM FORMAT
                REST    D0-D2,A5                ; REST REGISTERS
                RTN                             ; GO BACK

; CALC DAYS IN YEAR
                ; D6= YEAR PASSED

CALC.D:         CLR     D7                      ; PRE-CLEAR
                CLR     D0                      ; PRE-CLEAR
                DECW    D6                      ; SUB 1 FROM YEAR PASSED
                MOVW    D6,D0                   ; SAVE IT
                MUL     D0,#365.                ; MUL BY 365 DAYS A YEAR
                CLR     D1                      ; PRE-CLEAR
                MOVW    D6,D1                   ; GET YEAR
                DIV     D1,#4.                  ; DIV BY 4 = # OF LEAP YEARS
                AND     #177777,D1              ; ELIMINATE REMAINDER
                ADD     D1,D0                   ; ADD TO CUMULATIVE
                MOVW    D6,D1                   ; GET YEAR
                DIV     D1,#100.                ; CHECK FOR 100 YEAR EXCEPTIONS
                AND     #177777,D1              ; ELIMINATE REMAINDER
                SUB     D1,D0                   ; SUB FROM CUMULATIVE
                MOVW    D6,D1                   ; GET YEAR
                DIV     D1,#400.                ; CHECK FOR 400 YEAR EXCEPTIONS
                AND     #177777,D1              ; ELIMINATE REMAINDER
                ADD     D1,D0                   ; ADD TO CUMULATIVE
LEAP.YEAR:      INCW    D6                      ; RESET TO ORIGINAL YEAR PASSED
                CLR     D1                      ; PRE-CLEAR
                MOVW    D6,D1                   ; GET YEAR
                DIV     D1,#4.                  ; DIV BY 4 (PER LEAP YEAR CYCLE)
                SWAP    D1                      ; GET REMAINDER
                TSTW    D1                      ; CHECK FOR ZERO
                BNE     30$                     ; BR IF NOT
                MOVB    #1,D7                   ; SET LOW BYTE TO 1 - FLAG YES
10$:    ; CHECK FOR 100 YEAR EXCEPTION
                CLR     D1                      ; PRE-CLEAR
                MOVW    D6,D1                   ; GET YEAR
                DIV     D1,#100.                ; DIV BY 100 (CYCLE)
                SWAP    D1                      ; GET REMAINDER
                TSTW    D1                      ; IS IT ZERO
                BNE     30$                     ; BR IF NOT
                CLRB    D7                      ; YES SO UN SET FLAG
20$:    ; CHECK FOR 400 YEAR EXCEPTION
                CLR     D1                      ; PRE-CLEAR
                MOVW    D6,D1                   ; GET YEAR
                DIV     D1,#400.                ; DIV BY 400 (CYCLE)
                SWAP    D1                      ; GET REMAINDER
                TSTW    D1                      ; IS IT ZERO
                BNE     30$                     ; BR IF NOT
                MOVB    #1,D7                   ; YES SET FLAG
30$:            RTN                             ; ALL DONE

;CALC DAY OF WEEK
                ; D3=DATE AS DAYS

DOW:
                MOV     D3,D2                   ; SAVE DAYS
        ; ADJUST DAYS DIV HAS MAX LIMIT
                DIV     D2,#343.                ; DIV LARGE NUMBER DIV BY 7
                AND     #177777,D2              ; ELIMINATE REMAINDER
                BEQ     10$                     ; CONT IF NO QUO
                MUL     D2,#343.                ; MUST ADJUST CALC D2*343.
                SUB     D2,D3                   ; SUB FROM PASED NUMBER
10$:
                DIV     D3,#7.                  ; CALC MODULO 7
                SWAP    D3                      ; GET REMAINDER
                AND     #177777,D3              ; STRIP QUO
                RTN                             ; D3= DOW

                END