;* Updated on 16-Oct-89 at 9:03 PM by Ami Bar-Yadin; edit time: 0:06:03 *; ; Dates operations VMAJOR=1 VMINOR=2 VEDIT=107. ; ; [107] 16-Oct-89 Ami Bar-Yadin ; A bug in Function 8 ($IDTIM interface) was accidentaly discovered ; ; (C)1988 By Ami Bar-Yadin. ; AMUS ID: AMI/AM ; ;-All commercial rights reserved, etc. ;-No warranties and/or guarranties of any kind, etc. ;-Not responsible for damages resulting from the use of this program, etc. ;-My employer (United Fashions) has nothing to do with this program and ; should not be blamed for it. ; ; I can be reached at: ; United Fashions of Texas, Inc. ; 200 Ash Ave. ; McAllen, TX 78501 ; (512) 631-2277/2276 ; 8am-6pm ; ; ; Date formats: ; ASCII ADATE,S,8 ("01/05/83") S,8 ; ; Seperated XDATE X,{3..7} ; MONTH,B,1 ; DAY,B,1 ; YEAR,B,1 ; DOW,B,1 1=MON..7=SUN ; YWEEK,B,1 Week of year 1-52 ; MWEEK,B,1 Week of month 1-5 ; MDAYS,B,1 Days in month 1-31 ; ; Internal IDATE,B,4 True Julian B,4 ; AlphaBASE BDATE,B,3 Same as seperated X,3 above ; 16 bit CDATE,B,2 Century Julian B,2 ; Julian JDATE,F Yearly Julian F ; (assuming current year) ; ; ; SPECIAL CASE: ; ============ ; A floating point 0 will be converted to today's date on input. ; For example: ; XCALL DATES,1,RESULT,0,A$ ; Will return A$ with today's date. ; However: ; XCALL DATES,1,RESULT,TODAY,F ; (Where TODAY is todays date in any format) ; Will ALWAYS return a non-zero. ; ; ; FUNCTIONS: ; 1 XCALL DATES,1,RESULT,date,date ; Convert from any format to any format ; XCALL DATES,1,RESULT,ADATE,SDATE ; will convert an ASCII date to standard date ; ; 2 XCALL DATES,2,RESULT,date1,date2,days ; Will compute date2 = date1 + days ; ; 3 XCALL DATES,3,RESULT,date1,date2,days ; Will compute days = date1 - date2 ; ; 4 XCALL DATES,4,RESULT,date1,date2 ; Will compute date given year, week, and DOW ; date1 given as BDATE,X,5 or X,6 ; ; 5 XCALL DATES,5,RESULT,date1,date2 ; Will compute date given year, month, week and DOW ; date1 given as BDATE,X,6 ; ; 6 XCALL DATES,6,RESULT,date1,date2 ; Will compute date2=last day of month in date1 ; ; 7 XCALL DATES,7,RESULT,DATE,TIME,FLAGS,OUTPUT UFFER or FILE# ; (interface) $ODTIM: Output Date and Time (Time last) ; Entry: D3=Date, D4=time (0=use sys)(separated), D5=format flags,A2->out ; Return: A2->nxt char (if used) ; ; 8 XCALL DATES,8,RESULT,INPUT,FLAGS,OUTPUT DATE,OUTPUT TIME ; (interface) $IDTIM: Input Date and/or Time (if both, time must be first) ; Entry: A2->Input string, D5(bit 0)=1:no date,(bit 1)=1:no time ; Return: D3=date (separated), D4=time (separated), A2->nxt chr ; N set:error ; ; 9 XCALL DATES,9,RESULT,DATE,LODATE,HIDATE,DATEOK ; Check if DATE is between LODATE and HIDATE (inclusive) ; ie. DATEOK is <>0 if LODATE <= DATE <= HIDATE ; NOTE: DATEOK must be a floating point variable. ; ; ; RESULT (F) CODES: ; 0 ALL OK ; 1 FUNCTION NUMBER OUT OF RANGE (1..9) ; 2 ERROR IN CONVERSION OF INPUT DATE ; 3 INVALID FORMAT FOR DATE ; 4 IMPROPER NUMBER/TYPE OF PARAMETERS ; 5 INVALID FORMAT FOR DAYS ; 6 ERROR LOCATING FILE CHANNEL ; SYM OBJNAM .SBR SEARCH SYS SEARCH SYSSYM RADIX 16. DEFAULT $$MFLG,PV$RSM DEFAULT $$SFLG,PH$REE!PH$REU PHDR -1,$$MFLG,$$SFLG EXTERN $IDTIM,$DSTOI,$ODTIM,$FLSET ; ; CNTURY = 2415021. ; CONVERT IDATE<-->CDATE ; SOME BASIC XCALL INTERFACING MACROS ; ; Move the type field from the Nth parameter block off the ; BASIC XCALL parameters list into DEST ; DEFINE BTYPE N,DEST 1$$ = 2+^D10*<N-1> CLR DEST MOVW 1$$(A3),DEST ENDM ; ; ; Move the address field from the Nth parameter block off the ; BASIC XCALL parameters list into DEST ; DEFINE BADRS N,DEST 1$$ = 4+^D10*<N-1> MOVL 1$$(A3),DEST ENDM ; ; ; Move the size field from the Nth parameter block off the ; BASIC XCALL parameters list into DEST ; DEFINE BSIZE N,DEST 1$$ = 8+^D10*<N-1> MOVL 1$$(A3),DEST ENDM ; DATES: MOV SP,A5 ; SAVE STACK POINTER CALL SETUP CALL GETFUN ; GET FUNCTION VALUE (D0) 1..9 DEC D0 ; adjust to 0..8 CMP D0,#8. BHI 30$ ASL D0,#1 LEA A6,FTBL CLR D7 MOVW 0(A6)[~D0],D7 ADD D7,A6 JMP @A6 30$: MOV #1,D1 EXIT: BADRS 2,A0 ; SET RESULT CODE FLTOF D1,@A0 MOV A5,SP RTN DEFINE FUNCT ENTRY WORD ENTRY-FTBL ENDM FTBL: FUNCT CONVRT FUNCT COMPDT FUNCT COMPDY FUNCT COMPYW FUNCT COMPMW FUNCT COMPEM FUNCT IODTIM FUNCT IIDTIM FUNCT RNGEDT WORD 0 CONVRT: MOV #4,D1 CMPW @A3,#4 JNE EXIT CALL GETIDT ; CONVERT DATE1 TO INTERNAL FORMAT (D2) CALL PUTIDT ; CONVERT INTERNAL (D2) TO DATE2 CLR D1 BR EXIT ; SET RESULT AND EXIT COMPDT: MOV #4,D1 CMPW @A3,#5 JNE EXIT CALL GETIDT ; CONVERT DATE1 TO INTERNAL FORMAT (D2) CALL GETDAY ; GET NUMBER OF DAYS (D3) ADD D3,D2 ; D2=D2+D3 CALL PUTIDT CLR D1 BR EXIT COMPDY: MOV #4,D1 CMPW @A3,#5 JNE EXIT CALL GETIDT CALL GETID2 ; GET 2ND DATE (D3) SUB D3,D2 CALL PUTDAY ; SET NO OF DAYS (D2) CLR D1 BR EXIT COMPYW: MOV #4,D1 CMPW @A3,#4 JNE EXIT MOV #3,D1 BTYPE 3,D0 TST D0 JNE EXIT BSIZE 3,D0 CMP D0,#5 JLT EXIT BADRS 3,A2 MOV #01010000,D7 MOVB 2(A2),D7 CALL $DSTOI MOV D7,D3 ; D3=START'I'JUL SUB #CNTURY,D7 DIV D7,#7 SWAP D7 MOV D7,D4 ; D4=START'DOW ; I'JUL=START'I'JUL+(YWEEK-1)*7+DOW-START'DOW CLR D7 ; D7=0 MOVB 4(A2),D7 ; D7=YWEEK DECB D7 ; D7=YWEEK-1 MUL D7,#7 ; D7=(YWEEK-1)*7 ADD D3,D7 ; D7=START'I'JUL+(YWEEK-1)*7 CLR D3 MOVB 3(A2),D3 ; D3=DOW DEC D3 ; (PUT DOW IN 0..6 RANGE) ADD D3,D7 ; D7=START'I'JUL+(YWEEK-1)*7+DOW MOVB D4,D3 SUB D3,D7 ; D7=START'I'JUL+(YWEEK-1)*7+DOW-START'DOW MOV D7,D2 CALL PUTIDT CLR D1 JMP EXIT COMPMW: MOV #4,D1 CMPW @A3,#4 JNE EXIT MOV #3,D1 BTYPE 3,D0 TST D0 JNE EXIT BSIZE 3,D0 CMP D0,#6 JLT EXIT BADRS 3,A2 MOV #0100,D7 MOVB @A2,D7 SWAP D7 MOVB 2(A2),D7 CALL $DSTOI MOV D7,D3 ; D3=START'I'JUL SUB #CNTURY,D7 DIV D7,#7 SWAP D7 CLR D4 MOVB D7,D4 ; D4=START'DOW ; IF D'DOW=0 MWEEK=MWEEK-1 ; I'JUL=START'I'JUL+MWEEK*7+DOW-START'DOW CLR D7 ; D7=0 MOVB 5(A2),D7 ; D7=MWEEK ; TST D4 ; BEQ 1$ DECB D7 1$: MUL D7,#7 ; D7=MWEEK*7 ADD D3,D7 ; D7=START'I'JUL+MWEEK*7 CLR D3 MOVB 3(A2),D3 ; D3=DOW DEC D3 ; (PUT DOW IN 0..6 RANGE) ADD D3,D7 ; D7=START'I'JUL+MWEEK*7+DOW MOVB D4,D3 SUB D3,D7 ; D7=START'I'JUL+MWEEK*7+DOW-START'DOW MOV D7,D2 CALL PUTIDT CLR D1 JMP EXIT COMPEM: MOV #4,D1 CMPW @A3,#4 JNE EXIT CALL GETIDT ; CONVERT DATE1 TO INTERNAL FORMAT (D2) MOV D2,D7 CALL DITOS ; CONVERT TO SEPERATE FORMAT ADD #000010000,D7 ; MONTH=MONTH+1 AND #000FFFFFF,D7 ; DAY=0 CALL $DSTOI ; CONVERT BACK TO INTERNAL MOV D7,D2 CALL PUTIDT ; CONVERT INTERNAL (D2) TO DATE2 CLR D1 JMP EXIT ; SET RESULT AND EXIT IODTIM: ; 7 XCALL DATES,7,RESULT,DATE,TIME,FLAGS[,BUFFER or FILE#] ; (interface) $ODTIM: Output Date and Time (Time last) ; Entry: D3=Date, D4=time (0=use sys)(separated), D5=format flags,A2->out ; Return: A2->nxt char (if used) ; MOV #4,D1 ; ISSUE ERROR IF LESS THAN FIVE CMPW @A3,#5 JLO EXIT CMPW @A3,#6 ; OR MORE THAN SIX ARGUMENTS JHI EXIT CALL GETIDT ; CONVERT DATE1 TO INTERNAL FORMAT (D2) MOV D2,D7 CALL DITOS ; CONVERT TO SEPERATE FORMAT PUSH D7 MOV D2,D7 SUB #CNTURY,D7 DIV D7,#7 SWAP D7 AND #0FF,D7 ; MASK ALL BUT DOW MOVB D7,3(SP) ; SET DOW BADRS 4,A2 BTYPE 4,D0 BSIZE 4,D5 CALL GETNUM ;GET TIME ARG (D4) TST D3 ; if time=0 BNE 10$ GTIMES D3 ; get system time 10$: PUSH D3 BADRS 5,A2 BTYPE 5,D0 BSIZE 5,D5 CALL GETNUM ;GET FLAGS ARG (D5) PUSH D3 BADRS 6,A2 ;GET BUFFER ADDRESS OR FILE NUMBER ARG BTST #15.,D3 ;OUTPUT TO FILE? BEQ 20$ ;NO BTYPE 5,D0 BSIZE 5,D5 CALL GETNUM ;GET FILE CHANNEL NUMBER MOV D3,D1 CALL $FLSET ;FIND FILE'S DDB BEQ 20$ ;EVERYTHING'S OK, PROCEED MOV #6,D1 ;ERROR #6 BAD CHANNEL NUMBER JMP EXIT ;ABORT WITH ERROR 20$: POP D5 ;LOAD ARGS INTO PROPER REGISTERS POP D4 ; D3=DATE, D4=TIME, D5=FLAGS POP D3 CALL $ODTIM CLR D1 ;$ODTIM HAS NO ERROR CONDITIONS JMP EXIT ;RETURN TO CALLER IIDTIM: ; 8 XCALL DATES,7,RESULT,INPUT,FLAGS,OUTPUT DATE,OUTPUT TIME ; (interface) $IDTIM: Input Date and/or Time (if both, time must be first) ; Entry: A2->Input string, D5(bit 0)=1:no date,(bit 1)=1:no time ; Return: D3=date (separated), D4=time (separated), A2->nxt chr ; N set:error ; OUTPUT DATE AND TIME MUST BE B,4 ; ; ; MOV #4,D1 ; ISSUE ERROR IF NOT SIX ARGUMENTS CMPW @A3,#6 JNE EXIT BADRS 4,A2 BTYPE 4,D0 BSIZE 4,D5 CALL GETNUM ;GET FLAGS ARG (D5) MOV D3,D5 BADRS 3,A2 CALL $IDTIM BMI 1$ BADRS 5,A1 MOV D3,@A1 BADRS 6,A1 MOV D4,@A1 CLR D1 ;EVERYTHING OK JMP EXIT ;RETURN TO CALLER 1$: MOV #2,D1 JMP EXIT RNGEDT: ; 9 XCALL DATES,9,RESULT,DATE,LODATE,HIDATE,DATEOK ; Check if DATE is between LODATE and HIDATE (inclusive) ; ie. DATEOK is <>0 if LODATE <= DATE <= HIDATE ; BADRS 3,A2 ; get DATE BTYPE 3,D0 BSIZE 3,D5 CALL GETDAT PUSH D2 ; save DATE BADRS 4,A2 ; get LODATE BTYPE 4,D0 BSIZE 4,D5 CALL GETDAT POP D0 ; get DATE CMP D2,D0 ; compare LODATE to DATE BHI 50$ ; LODATE > DATE; DATE out of range PUSH D0 ; save DATE BADRS 5,A2 ; get HIDATE BTYPE 5,D0 BSIZE 5,D5 CALL GETDAT MOV #-1,D1 ; assume DATE is in range POP D0 ; get DATE CMP D2,D0 ; compare HIDATE to DATE BHIS 99$ ; HIDATE >= DATE; DATE ok 50$: CLR D1 99$: BADRS 6,A0 ; SET RESULT CODE FLTOF D1,@A0 CLR D1 JMP EXIT GETIDT: ; CONVERT DATE1 TO INTERNAL (D2) SAVE A2,D0,D3,D4,D7 BADRS 3,A2 BTYPE 3,D0 BSIZE 3,D5 CALL GETDAT REST A2,D0,D3,D4,D7 CLR D1 RTN GETID2: ; CONVERT DATE2 TO INTERNAL (D3) SAVE A2,D0,D2,D4,D7 BADRS 4,A2 BTYPE 4,D0 BSIZE 4,D5 CALL GETDAT MOV D2,D3 REST A2,D0,D2,D4,D7 RTN PUTIDT: ; CONVERT INTERNAL (D2) TO DATE2 SAVE A2,D0,D2,D3,D4,D5 BADRS 4,A2 BTYPE 4,D5 BSIZE 4,D0 CMP D5,#2 JEQ PTDASC CMP D5,#4 JEQ PTDF CMP D5,#6 JEQ PTDB MOV #3,D1 TST D5 JNE EXIT ; UNFORMATTED (X), 1ST 3 BYTES ARE ALWAYS: MONTH,DAY,YEAR PTDX: MOV D2,D7 CALL DITOS MOV D7,D3 PUSH D6 ; # OF DAYS IN MONTH MOVB D7,2(A2) ; SET YEAR SWAP D7 MOVB D7,@A2 ; SET MONTH RORW D7,#8 MOVB D7,1(A2) ; SET DAY CMP D0,#4 JLO PTDEXT MOV D2,D7 SUB #CNTURY,D7 DIV D7,#7 SWAP D7 AND #0FF,D7 ; MASK ALL BUT DOW INCB D7 ; (PUT DOW IN 1..7 RANGE) MOVB D7,3(A2) ; SET DOW CMP D0,#5 JLO PTDEXT ;YWEEK=INT((NOW-START+START'DOW)/7)+1 MOV D3,D7 AND #0000FFFF,D7 OR #01010000,D7 ; SET MONTH AND DAY=01/01 CALL $DSTOI ; D7=START MOV D2,D5 ; D5=NOW SUB D7,D5 SUB #CNTURY,D7 DIV D7,#7 SWAP D7 AND #0FF,D7 ; MASK ALL BUT DOW ADD D7,D5 DIV D5,#7 INCB D5 MOVB D5,4(A2) CMP D0,#6 BLO PTDEXT ;MWEEK=INT((NOW-START+START'DOW)/7)+1 MOV D3,D7 AND #00FFFFFF,D7 OR #01000000,D7 ; SET DAY=01 CALL $DSTOI ; D7=START MOV D2,D5 ; D5=NOW SUB D7,D5 SUB #CNTURY,D7 DIV D7,#7 SWAP D7 AND #0FF,D7 ; MASK ALL BUT DOW ADD D7,D5 DIV D5,#7 MOVB D5,5(A2) ; TSTB D7 ; BEQ 1$ INCB 5(A2) 1$: CMP D0,#7 BLO PTDEXT ;MDAYS MOV @SP,D6 MOVB D6,6(A2) PTDEXT: POP CLR D1 REST A2,D0,D2,D3,D4,D5 RTN PTDASC: MOV D2,D7 CALL DITOS MOV D7,D3 MOV #840.,D5 CALL $ODTIM CMP D0,#8 BLE PTDEXT CLRB @A2 JMP PTDEXT PTDB: CMP D0,#3 JEQ PTDX ; B,3 SAME AS X,3 MOV A2,D3 BTST #0,D3 JNE ADRERR CMP D0,#4 BEQ PTDB4 ; ASSUME B,2 FORMAT MOV D2,D3 SUB #CNTURY,D3 MOVW D3,@A2 ; SET DAYS JMP PTDEXT PTDB4: MOV D2,D3 SWAP D3 ; TO FIT BASIC'S B,4 FORMAT MOV D3,@A2 JMP PTDEXT PTDF: MOV D2,D7 CALL DITOS AND #0000FFFF,D7 OR #01010000,D7 ; SET MONTH AND DAY=01/01 CALL $DSTOI MOV D2,D3 SUB D7,D3 INC D3 FLTOF D3,@A2 JMP PTDEXT GETDAY: ; GET NUMBER OF DAYS (D3) SAVE A2,D0,D5 BADRS 5,A2 BTYPE 5,D0 BSIZE 5,D5 CALL GETNUM REST A2,D0,D5 RTN GETNUM: CMP D0,#4 ;CHECK IF ARG IS FLOATING POINT BNE 1$ FFTOL @A2,D3 ;CONVERT FLOATING POINT ARG BR 3$ ;BRANCH TO ROUTINE EXIT 1$: MOV #5,D1 ;(ASSUME ERROR#5) CMP D0,#6 ;CHECK IF ARG IS BINARY JNE EXIT ;ABORT PROGRAM WITH ERROR IF IMPROPER TYPE CMP D5,#5 ;CHECK LENGTH OF ARG IN BYTES JEQ EXIT ;ABORT PROGRAM WITH ERROR IF TOO LONG ADD D5,A2 ;COMPUTE POINTER TO BYTE PAST ARG CLR D3 ;CLEAR DESTINATION 2$: LSL D3,#8 ;PREPEARE FOR NEXT BYTE MOVB -(A2),D3 ;LOAD NEXT BYTE SOB D5,2$ ;LOOP UNTIL DONE 3$: CLR D1 ;NO ERRORS RTN PUTDAY: ; SET NUMBER OF DAYS (D2) SAVE A2,D0,D2,D5 BADRS 5,A2 BTYPE 5,D0 BSIZE 5,D5 CALL PUTNUM REST A2,D0,D2,D5 RTN PUTNUM: CMP D0,#4 BNE 0$ FLTOF D2,@A2 BR 2$ 0$: MOV #5,D1 TST D0 JNE EXIT CMP D5,#5 JEQ EXIT 1$: MOVB D2,(A2)+ LSR D2,#8 SOB D5,1$ 2$: CLR D1 RTN SETUP: ; SETUP RTN GETFUN: ; GET FUNCTION NUMBER (D0) PUSH A2 BADRS 1,A2 FFTOL @A2,D0 POP A2 RTN ; DITOS: ; CONVERT INTERNAL DATE (D7) TO SEPERATED DATE (D7), ; SET D6 TO NUMBER OF DAYS IN MONTH ; D2=MONTH ; D3=DAY ; D4=YEAR ; SAVE D2,D3,D4,A2,A3 CMP D7,#CNTURY BHIS 0$ CLR D7 BR 10$ 0$: SUB #CNTURY,D7 10$: DIV D7,#05B5 CLR D3 MOVW D7,D3 ADDW D3,D3 ADDW D3,D3 CLRW D7 SWAP D7 DIV D7,#016D ADDW D7,D3 CLR D4 MOVW D3,D4 TSTW D7 BEQ 1$ LEA A2,NORMYR LEA A3,NORMDS SWAP D7 BR 2$ 1$: LEA A2,LEAPYR LEA A3,LEAPDS SWAP D7 INCW D7 2$: MOVW #-1,D3 3$: INCW D3 CMPW D7,(A2)+ BCC 3$ CLR D2 MOVW D3,D2 SUB #4,A2 SUBW @A2,D7 CLR D3 MOVW D7,D3 INC D3 ; DY MN DW YR CLR D7 ; D7=00 00 00 00 MOVB D3,D7 ; D7=00 00 00 D3 RORW D7,#8 ; D7=00 00 D3 00 MOVB D2,D7 ; D7=00 00 D3 D2 SWAP D7 ; D7=D3 D2 00 00 MOVB D4,D7 ; D7=D3 D2 00 D4 MOVB -1(A3)[~D2],D6 REST D2,D3,D4,A2,A3 RTN RADIX 10. NORMYR: WORD 0,31,59,90,120,151,181,212,243,273,304,334,365 LEAPYR: WORD 0,31,60,91,121,152,182,213,244,274,305,335,366 NORMDS: BYTE 31,28,31,30,31,30,31,31,30,31,30,31 LEAPDS: BYTE 31,29,31,30,31,30,31,31,30,31,30,31 RADIX 16. ; GETDAT: CMP D0,#2 JEQ GTDASC CMP D0,#4 JEQ GTDF CMP D0,#6 JEQ GTDB MOV #3,D1 TST D0 JNE EXIT ; UNFORMATTED (X), 1ST 3 BYTES ARE ALWAYS: MONTH,DAY,YEAR GTDX: CLR D7 MOVB 1(A2),D7 RORW D7,#8 MOVB @A2,D7 SWAP D7 MOVB 2(A2),D7 GTDEXT: TST D7 BEQ 1$ CALL $DSTOI 1$: MOV D7,D2 RTN GTDASC: MOVB 8(A2),D1 CLRB 8(A2) MOV #2,D5 PUSH A2 CALL $IDTIM SETNE D2 POP A2 MOVB D1,8(A2) MOV #2,D1 TSTB D2 JNE EXIT MOV D3,D7 JMP GTDEXT GTDB: CMP D5,#3 JEQ GTDX MOV A2,D2 BTST #0,D2 JNE ADRERR CMP D5,#4 BEQ GTDB4 CLR D2 MOVW @A2,D2 ADD #CNTURY,D2 RTN GTDB4: MOV @A2,D2 SWAP D2 ; CONVERT FROM BASIC'S B,4 FORMAT RTN GTDF: FFTOL @A2,D2 BEQ 1$ DEC D2 GDATES D7 ; GET TODAY'S DATE AND #0000FFFF,D7 OR #01010000,D7 ; SET MONTH AND DAY=01/01 CALL $DSTOI ADD D7,D2 RTN 1$: GDATEI D2 RTN ; ADRERR: TYPECR <?Odd address given to DATES.SBR as WORD or LONG> EXIT ; END