home *** CD-ROM | disk | FTP | other *** search
- DOSSEG
- .MODEL SMALL
- .STACK 100H
- .DATA
- Program DB 13,10,"Days Between Dates calculation",13,10
- Version DB "1.11 (c) 1988 by Tom Gilbert's Heart&Mind",13,10
- Usage DB "ONLY NON-Commercial useage authorized",13,10,10
- Syntax DB "Syntax >DBD mm/dd/yyyy[bc] [MM/DD/YYYY[BC]]",13,10
- Limits DB "Limits from 01/01/4004BC to 12/31/9999",7,7,13,10,0
- Report DB 13,10,10 DUP(' ')
- DateS1 DB 12 DUP(' ')," is "
- DBDStr DB 12 DUP(' ')," days "
- BeOrAf DB "after",12 DUP(' ')
- DateS2 DB " / /",7 DUP(' '),13,10,0
- Before DB "before"
- SameAs DB "the same date as"
- DayTbl DB " Sunday"," Monday"," Tuesday","Wednesday"
- DB " Thursday"," Friday"," Saturday"
- Y1Huns DB ?
- Y1Ones DB ? ; Year
- Mon1No DB ? ; Month
- Day1No DB ? ; DayOfMonth
- Y2Huns DB ? ; Array
- Y2Ones DB ? ; for 2
- Mon2No DB ? ; Dates
- Day2No DB ?
- MaxDay DB 0,31,29,31,30,31,30,31,31,30,31,30,31
- PSP DW ?;JanFebMarAprMayJunJulAugSepOctNovDec
- MonDay DW 0,31,59,90,120,151,181,212,243,273,304,334
- D1Days DD ?
- D2Days DD ?
- .CODE
- EXTRN ArgC:Proc,ArgV:Proc,B2Dec:Proc
- Main Proc Far
- Mov AX,@data ; Make Data
- Mov DS,AX ; Addressable
- Mov PSP,ES ; Preserve PSP
- Mov ES,AX ; for later use
- Mov AH,2Ah ; Get Current
- Int 21h ; DOS Date and
- Mov BX,OFFSET DateS2 ; Position to
- Mov AL,DH ; Store ASCII
- Call B2Dec ; Decimal Month
- Add BX,3 ; Position to
- Mov AL,DL ; Store ASCII
- Call B2Dec ; Decimal Day of Month
- Add BX,3 ; Position to Store
- Mov AX,100 ; Hundreds
- Xchg AX,CX ; and the
- Xor DX,DX ; Remaining
- Div CX ; Years
- Call B2Dec ; Store Century and
- Add BX,2 ; Position to Store
- Mov AL,DL ; Remaining Years
- Call B2Dec ; Decimal Digits
- Mov ES,PSP ; Restore PSP to
- Mov BX,80h ; Get Command Line
- Call ArgC ; Argument Count
- Dec AX ; If Any Dates
- Jnz OneTwo ; Then How Many?
- Jmp HelpM ; Else Give Help
- OneTwo: Cmp AX,1 ; If Only One
- Mov AX,10 ; Then Use 10
- Jz S2Date ; Byte DOS Date 2
- Mov DI,OFFSET DateS2 ; Else Get Date 2
- Mov AX,2 ; from Command
- Call GetArg ; Line Argument
- S2Date: Mov SI,OFFSET DateS2 ; Set Source
- Mov CX,AX ; Date length
- Push DS ; and Extra
- Pop ES ; Segment for
- Mov DI,OFFSET Mon2No ; Destination
- Call ValDate ; If Valid Date
- Jz Valid2 ; Then Continue
- Jmp HelpM ; Else Give Help
- Valid2: Mov DI,Offset DateS2 ; If Date
- Mov CX,12 ; string
- Mov AL,"B" ; has
- RepNE ScaSB ; "BC"
- Je DDate2 ; Then Do Date 2
- Mov Word Ptr D2Days[2],16h ; Else Initialize
- Mov Word Ptr D2Days[0],509Eh; Days AnoDomenei
- DDate2: Mov DI,OFFSET D2Days ; Set Destination
- Mov BP,OFFSET DateS2-2 ; Day and DayName
- Mov SI,OFFSET Y2Huns ; and Source Pointers
- Call DoDays ; Get Days and DayName
- Mov ES,PSP ; Set ES to PSP
- Mov AX,1 ; to Call 4 Date 1
- Mov DI,OFFSET DateS1 ; from Command
- Call GetArg ; Line Argument
- Mov SI,OFFSET DateS1 ; Set Source
- Mov CX,AX ; Date length
- Push DS ; and Extra
- Pop ES ; Segment for
- Mov DI,OFFSET Mon1No ; Destination
- Call ValDate ; If Valid Date
- Jz Valid1 ; Then Continue
- Jmp HelpM ; Else Give Help
- Valid1: Mov DI,Offset DateS1 ; If Date
- Mov CX,12 ; string
- Mov AL,"B" ; has
- RepNE ScaSB ; "BC"
- Je DDate1 ; Then Do Date 1
- Mov Word Ptr D1Days[2],16h ; Else Initialize
- Mov Word Ptr D1Days[0],509Eh; Days AnoDomenei
- DDate1: Mov DI,OFFSET D1Days ; Set Destination
- Mov BP,OFFSET DateS1-2 ; Day and DayName
- Mov SI,OFFSET Y1Huns ; and Source Pointers
- Call DoDays ; Get Days and DayName
- Mov AX,Word Ptr D1Days[0] ; If First Date
- Mov DX,Word Ptr D1Days[2] ; MSW Less Than
- Sub DX,Word Ptr D2Days[2] ; Second Date
- Jb BefStr ; Then is "before"
- Sub AX,Word Ptr D2Days[0] ; Else If LSW Less
- Jb DecMSW ; Then Borrow
- Jnz DoTot ; Else "after" Ok
- Mov SI,OFFSET SameAs ; Else "the same
- Mov DI,OFFSET BeOrAf-11 ; date as"
- Mov CX,16 ; String to move
- Rep MovSB ; and exit with
- Jmp SHORT ReptM ; NO Days Between
- DecMSW: Sub DX,1 ; If Borrow is Ok
- Jnc DoTot ; Then "after" Ok
- BefStr: Mov SI,OFFSET Before ; Move "before" to
- Mov DI,OFFSET BeOrAf ; replace "after "
- Mov CX,6 ; six bytes
- Rep MovSB
- Mov AX,Word Ptr D2Days[0] ; Get Larger
- Mov DX,Word Ptr D2Days[2] ; Days in DX:AX
- Sub AX,Word Ptr D1Days[0] ; Subtract the
- Sbb DX,Word Ptr D1Days[2] ; Lesser for Total
- DoTot: Mov CX,10 ; Put Decimal ASCII
- Mov BP,9 ; 9 Place String in
- Mov DI,OFFSET DBDStr ; Display Area
- DDLoop: Call Divide ; Divide by 10
- Add BL,"0" ; Make Result
- Mov ES:[DI+BP],BL ; ASCII and Store
- Dec BP ; Move Index Left
- Cmp BP,6 ; After Each
- Jnz CkBP2 ; Three Digits
- CkAX0: Or AX,DX ; Unless
- Jz ReptM ; Done -
- Mov Byte Ptr ES:[DI+BP],"," ; Comma
- Dec BP ; Count and
- Jmp SHORT DDLoop ; Continue
- CkBP2: Cmp BP,2 ; If nnn,nnn
- Jz CkAX0 ; Then Comma/Done?
- Or AX,DX ; Else Continue
- Jnz DDLoop ; Until 0 Remains
- ReptM: Mov SI,OFFSET Report ; Show DBD Report
- Jz BytL ; Unless Error and
- HelpM: Mov SI,OFFSET Program ; Then Give Help
- BytL: LodSB ; If NOT
- Cmp AL," " ; Space
- Jnz Ck40 ; Then Done?
- Cmp AL,DL ; Else If Double
- Jz BytL ; Then Skip
- Ck40: Or AL,AL ; Else If 0
- Jz Exit ; Then Done
- Mov DL,AL ; Else Send
- Mov AH,2 ; Byte to
- Int 21h ; Console
- Jmp SHORT BytL ; Until 0
- Exit: Mov AH,4Ch ; Exit to
- Int 21h ; MS-DOS
- Main EndP
-
- GetArg Proc
- Mov BX,80h ; Get Command
- Call ArgV ; Line Argument
- Push DS ; for Transfer
- Push ES ; into ES:DI
- Pop DS ; from DS:SI
- Pop ES
- Mov SI,BX
- Mov CX,AX ; Set Number of
- Rep MovSB ; Bytes to Move
- Mov CX,10 ; If All 10
- Sub CX,AX ; Places Used
- Jcxz EndSpc ; Then NO Spaces
- Push AX ; Are Necessary
- Mov AL," " ; Else Store
- Rep StoSB ; Spaces to Fill-
- Pop AX ; Out Date String
- EndSpc: Push DS ; Swap
- Push ES ; Segments
- Pop DS ; Back to
- Pop ES ; Original
- Ret
- GetArg EndP
-
- Divide Proc Near
- Push AX ;Preserve Dividend LSW
- Mov AX,DX ;While Process MSW
- Xor DX,DX ;Zero Divide Extension
- Div CX ;Divide MSW and
- Mov BX,AX ;Save Remainder
- Pop AX ;Restore LSW and
- Div CX ;Get its Remainder
- Xchg BX,DX ;Restore and Return
- Ret ;DX:AX remainder & BX Result
- Divide EndP
-
- ValDate Proc
- Mov BP,10 ; Set Decimal Base
- NewNum: Xor BX,BX ; Zero Accumulator
- GVNNLp: LodSB ; If Byte
- Sub AL,"0" ; is NOT
- Jc EndNum ; Decimal
- Cmp AL,10 ; Digit
- Jnc EndNum ; Then End Number
- Sub AH,AH ; Else Calculate
- Xchg AX,BX ; accumulated
- Mul BP ; places plus
- Add BX,AX ; new value
- Loop GVNNLp ; Until AD
- EndNum: Jcxz StorYr ; Date Ends
- Mov AH,"0" ; Or Until
- Add AH,AL ; High and
- Mov AL,[SI] ; Low Byte
- And AX,5F5Fh ; UpperCase
- Cmp AX,"BC" ; is "BC"
- Je BC_Era ; Then BC Ends
- Mov AL,BL ; Else Store
- StoSB ; Month or Day
- Loop NewNum ; Loop Until End
- Cmp CX,1 ; Or an Error
- Jmp SHORT ExitVD ; is Detected
- BC_Era: Cmp BX,4004 ; If > 4004 BC
- Ja ExitVD ; Then Error Exit
- Neg BX ; Else Make BC
- Add BX,4005 ; Reciprocal
- And Word Ptr [SI-1],5F5Fh ; Insure "yyyyBC"
- StorYr: Mov AX,BX ; Convert Years
- Mov CX,100 ; into Hundreds
- Xor DX,DX ; and Remaining
- Div CX ; years and
- Mov [DI-4],AL ; Store Century
- Mov [DI-3],DL ; and Remainder
- Mov DX,[DI-2] ; If Month
- Cmp DL,1 ; Is < 1
- Jc ExitVD ; Or If Day
- Cmp DH,1 ; of Month < 1
- Jc ExitVD ; Or If Month
- Cmp DL,12 ; Is > 12
- Ja ExitVD ; Then Error Exit
- Mov AX,BX ; Else Get Year
- Push BX ; Preserve Year
- Mov CX,4 ; and MOD 4 to
- Xor DX,DX ; Check 4 Leap
- Call Divide ; If Year MOD 4
- Or BX,BX ; is Zero for
- Mov AX,0 ; a Leap Year
- Jz LeapY ; Or If Month
- Cmp Byte Ptr [DI-2],2 ; NOT February
- Jnz LeapY ; Then Table Ok
- Dec AX ; Else Feb = 28
- LeapY: Mov BL,[DI-2] ; Set Pointer to
- Xor BH,BH ; MaxDay Offset
- Add AL,MaxDay[BX] ; Get MAXimum
- Pop BX ; Restore Year
- Cmp [DI-1],AL ; If DayOfMonth > MAX
- Ja ExitVD ; Then Error Exit
- Xor AX,AX ; Else ZR Flag Ok
- ExitVD: Ret
- ValDate EndP
-
- DoDays Proc ; Preserve DayName
- Push BP ; Storage Pointer
- Dec BX ; Year - 1 =
- Mov BP,BX ; Years Past
- Mov AX,365 ; Days/Year
- Xchg AX,BX ; Calculate and
- Mul BX ; Store Days
- Add Word Ptr [DI+0],AX ; Except for
- Adc Word Ptr [DI+2],DX ; Leap Years
- Cmp Byte Ptr [SI+2],3 ; If Month < 3
- Jc AdDays ; Then Don't
- Mov AX,BP ; Else Restore
- Inc AX ; Current Year
- Mov CX,4 ; Check MOD 4
- Call Divide ; If Year MOD 4
- Or BX,BX ; is NOT 0
- Jnz AdDays ; Then Add Days
- Inc BP ; Else Inc Year
- AdDays: Mov BL,[SI+2] ; Get mm/dd
- Xor BH,BH ; Month Word
- Shl BX,1 ; Pointer to
- Mov AX,MonDay[BX-2] ; Days to Month
- Add AL,[SI+3] ; + Day of Month
- Adc AH,0 ; = Days in Year
- Add Word Ptr [DI+0],AX ; Total the
- Adc Word Ptr [DI+2],0 ; Days to Date
- Mov AX,BP ; Get Year
- Mov BX,4 ; For Each
- Xor DX,DX ; 4 Years
- Div BX ; Add a
- Add Word Ptr [DI+0],AX ; Leap
- Adc Word Ptr [DI+0],0 ; Year
- Mov AX,BP ; Except
- Mov BX,100 ; Years
- Xor DX,DX ; in even
- Div BX ; Centuries
- Sub Word Ptr [DI+0],AX ; Are NOT
- Sbb Word Ptr [DI+2],0 ; Leap Years
- Mov AX,BP ; Unless Even
- Mov BX,400 ; 4th Century
- Xor DX,DX
- Div BX
- Add Word Ptr [DI+0],AX
- Adc Word Ptr [DI+0],0
- Mov AX,BP ; Except
- Mov BX,4000 ; Years
- Xor DX,DX ; in even
- Div BX ; 4000 years
- Sub Word Ptr [DI+0],AX ; Are NOT
- Sbb Word Ptr [DI+2],0 ; Leap Years
- Mov AX,Word Ptr [DI+0] ; Get 32 bit
- Mov DX,Word Ptr [DI+2] ; Days for Date
- Cmp DX,16h ; If < for 4004
- Jc Ok4Day ; Then Ready
- Sub DX,16h ; Else Subtract
- Sub AX,509Eh ; days for 4004
- Sbb DX,0
- Ok4Day: Mov CX,7 ; Calculate
- Call Divide ; Day Code
- Mov AX,BX ; for Day
- Mov CX,9 ; Name
- Mov SI,OFFSET DayTbl-1 ; Table
- Std ; Backward
- Pop DI ; Transfer
- Add SI,CX ; from end
- Mul CL ; of Name
- Add SI,AX ; in Table
- Rep MovSB ; to DayName
- Cld ; Destination
- Ret
- DoDays EndP
- End Main
-