;       SCCSID = @(#)ctime.asm	6.1 90/11/18
;	SCCSID = @(#)ctime.asm      13.3 90/02/13
;***	ctime.asm -  map internal to external times and vice-versa
;
;	Copyright Microsoft, 1989.

.286

.MODEL MEDIUM, PASCAL

ifdef MEDIUM_MODEL
CALLTYPE    equ <far>
else
CALLTYPE    equ <near>
endif

.DATA

;**	Net_To_Dos_Date - convert path name to pinball form

_70_TO_80_BIAS      equ	12CEA600h
high_70_TO_80_BIAS  equ     12CEh
low_70_TO_80_BIAS   equ    0A600h

TSEC_IN_MIN     equ     30      ; # of two-second units in a minute
MIN_IN_HOUR     equ     60
HOURS_IN_DAY    equ     24
TSEC_IN_DAY     equ     HOURS_IN_DAY * MIN_IN_HOUR * TSEC_IN_MIN
DAYS_IN_4YEARS	equ     (3*365+366)

YEAR_TAB        dw  366, 365, 365, 365

LEAP_MONTH_TAB  dw  31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ; Leap year
MONTH_TAB       dw  31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ; Non-leap

YEAR_CNT        dw  0, 366, 366+365, 366+365+365   ; Days since last leap year.

; Days in current year up to current month.
MONTH_CNT   dw  0, 31, 31+29, 31+29+31, 31+29+31+30, 31+29+31+30+31; Leap year
            dw  31+29+31+30+31+30, 31+29+31+30+31+30+31
            dw  31+29+31+30+31+30+31+31, 31+29+31+30+31+30+31+31+30
            dw  31+29+31+30+31+30+31+31+30+31, 31+29+31+30+31+30+31+31+30+31+30

            dw  0, 31, 31+28, 31+28+31, 31+28+31+30, 31+28+31+30+31; Non-leap
            dw  31+28+31+30+31+30, 31+28+31+30+31+30+31
            dw  31+28+31+30+31+30+31+31, 31+28+31+30+31+30+31+31+30
            dw  31+28+31+30+31+30+31+31+30+31, 31+28+31+30+31+30+31+31+30+31+30

IRP SEG,<_TEXT,_BTXT>

.CODE SEG

PUBLIC Net_To_Dos_Date&SEG
Net_To_Dos_Date&SEG proc CALLTYPE    \
        USES SI DS,     \
        TIME:dword,     \
        PDOSDATE:dword, \
        PDOSTIME:dword


        mov     AX,_DATA
        mov     DS,AX
        mov     AX,word ptr TIME
        mov     DX,word ptr TIME + 2

; DX:AX = Time in sec since 1-1-70

        sub     AX,low_70_TO_80_BIAS
        sbb     DX,high_70_TO_80_BIAS

; DX:AX = Time in sec since 1-1-80

        shr     DX,1
        rcr     AX,1

; DX:AX = Time in 2-sec units since 1-1-80

        mov     BX,TSEC_IN_DAY
        div     BX

; AX = Days since 1-1-80.  DX = 2-sec since last midnight (time-of-day).

        mov     BX,DX                   ; Save time-of-day in BX.
        xor     DX,DX
        mov     CX,DAYS_IN_4YEARS
        div     CX
        xchg    DX,AX                   ; DX = Number of 4Years since 1980.
        shl     DX,2                    ; DX = DX * 4.

; AX = Days since (and including) last leap year.
; DX = Years since 1980 till (and excluding) last leap year.

        mov     SI,-2
NTDD0:
        add     SI,2
        sub     AX,YEAR_TAB[SI]
        jge     NTDD0                   ; Next year.
        add     AX,YEAR_TAB[SI]         ; Fix Overrun.
        shr     SI,1                    ; SI = Years since last leap year.
        add     DX,SI

; AX = Days in this year.
; DX = Years since 1980.

        test    SI,3                         ; Is it a leap year ?
        je      NTDD2                        ; Yes.
        mov     SI,offset MONTH_TAB - 2      ; Use non-leap year table.
NTDD1:
        add     SI,2
        sub     AX,[SI]
        jge     NTDD1                        ; Next month.
        add     AX,[SI]                      ; Fix Overrun.
        sub     SI,offset MONTH_TAB          ; Used non-leap year table.
        jmp     NTDD4
NTDD2:
        mov     SI,offset LEAP_MONTH_TAB - 2 ; Use leap year table.
NTDD3:
        add     SI,2
        sub     AX,[SI]
        jge     NTDD3                        ; Next month.
        add     AX,[SI]                   ; Fix Overrun.
        sub     SI,offset LEAP_MONTH_TAB     ; Used leap year table.
NTDD4:

; DX = Year, SI = Month * 2, AX = Day.

; Dos Date       __________________________
;		| years |  months |  days  |
;		| 7 bit |  4 bits | 5 bits |
;		|__________________________|
; years  : 0 = 1980.
; months : 1 = january.
; days   : 1 = 1st day of the month.


        add     SI,2                    ; Dos format: jan = 1.
        inc     AL                      ; Dos format: 1st = 1.
        shl     DL,1
        mov     AH,DL
        shl     SI,4
        or      AX,SI                   ; AX = Dos Date.

        xchg    AX,BX                   ; BX = Dos Date, AX = Time-of-day.

        xor     DX,DX                   ; DX:AX = Time-of-day
        mov     CX,TSEC_IN_MIN
        div     CX                      ; AX = Min in day, DX = 2sec.
        mov     CL,MIN_IN_HOUR          ; AL = Hour, AH = Min.
        div     CL                      ; AL = Hour, AH = Min.
        xchg    AL,AH                   ; AH = Hour, AL = Min.
; Dos Time	 __________________________
;		| hours | minutes | seconds|
;		| 5 bit |  6 bits | 5 bits+|
;		|__________________________|

        shl     AL,2
        shl     AX,3
        or      AX,DX                   ; AX = Dos Time.

        lds     SI,PDOSTIME
        mov     DS:[SI],AX
        lds     SI,PDOSDATE
        mov     DS:[SI],BX
        ret

Net_To_Dos_Date&SEG endp



PUBLIC Dos_To_Net_Date&SEG
Dos_To_Net_Date&SEG proc CALLTYPE    \
        USES SI DS,     \
        DOSDATE:word,   \
        DOSTIME:word

        mov     AX,_DATA
        mov     DS,AX
        mov     BX,DOSDATE          ; BX = Dos date.
        mov     AL,BH
        xor     AH,AH
        mov     SI,AX
        and     SI,6                ; SI = Index into YEARS_CNT.
        shr     AX,3                ; AX = Years since 1980 DIV 4.
        mov     DX,DAYS_IN_4YEARS
        mul     DX
        add     AX,YEAR_CNT[SI]

; AX = Days in years since 1980 excluding current year.

        mov     DX,BX
        shr     DX,4
        and     DX,001Eh            ; DX = Month * 2.
        test    SI,6                ; Is it a leap year ?
        mov     SI,-2               ; Compansate for DX (january = 2).
        je      DTND0               ; Yes.
        mov     SI,22               ; No - use non-leap year table.
DTND0:
        add     SI,DX
        add     AX,MONTH_CNT[SI]
        and     BX,1Fh              ; BX = Days in current month.
        dec     BX                  ; Dos Date : 1 = 1st day of the month.
        add     AX,BX               ; AX = Days since 1-1-80
        mov     DX,TSEC_IN_DAY
        mul     DX                  ; DX:AX = 2sec til last midnight.
        mov     CX,DX
        mov     BX,AX               ; Save 2sec til last midnight in CX:BX.

        mov     DX,DOSTIME          ; DX = Dos time.
        mov     AL,DH
        shr     AL,3                ; AL = Hours.
        mov     AH,MIN_IN_HOUR
        mul     AH
        mov     SI,DX
        shr     SI,5
        and     SI,003Fh            ; SI = Minutes from DOSTIME.
        add     AX,SI               ; AX = Minutes since midnight.
        mov     SI,DX
        and     SI,001Fh            ; SI = 2sec from DOSTIME.
        mov     DX,TSEC_IN_MIN
        mul     DX
        add     AX,SI
        adc     DX,0                ; DX:AX = 2sec since midnight.
        add     AX,BX
        adc     DX,CX
        shl     AX,1
        rcl     DX,1
        add     AX,low_70_TO_80_BIAS
        adc     DX,high_70_TO_80_BIAS
        ret

Dos_To_Net_Date&SEG endp

ENDM
END
