
*       Day2Day
*
*	Calculates the difference between two dates (in days).
*
*
*	NOTE:	There's no need to 'RUN' or 'RUNBACK' this program from the
*		CLI. It is auto-detaching.
*
*HISTORY
*         Made with Hisoft V2.12
*  V1.0   27-Jul-91: Made the calculation and parsing routines. Works fine.
*                    Added intuition interface.
*         28-Jul-91: Rewrote calculation routine - now much faster (but still
*                    not optimal).
*                    Added date validity-check.

	OPT O+
	OPT O1+			; Tells when a branch could be optimised to short
	OPT i+			; Tells when '#' is probably missing

		incdir		"AsmInc:"
		include		"P.i"
		include		"Intui.i"
		include		"Detach.i"
		include		"relMacros.i"
		include		"intuition/intuition.i"
		include		"intuition/intuition_lib.i"
		include		"libraries/dosextens.i"

DB		EQUR		A4

 dcDeclare	A4
 dcAPtr		WBenchMsg
 dcAPtr		IntuiBase
 dcAPtr		DWindow
 dcAPtr		Up
 dcAPtr		Rp
 dcLong		Class
 dcAPtr		IAddress
 dcArea		FromInfo,si_SIZEOF
 dcArea		ToInfo,si_SIZEOF
 dcArea		FromBuf,11
 dcArea		ToBuf,11
 dcEnd

Start		DetachSingle	<'Day2Day'>,4000,0
		dcAlloc					; Allocate memory for variables
		dcReset					; Clear the memory
		lea		FromGad(PC),A1
		lea		FromInfo(DB),A2
		move.l		A2,gg_SpecialInfo(A1)
		lea		FromBuf(DB),A1
		move.l		A1,si_Buffer(A2)
		move.w		#11,si_MaxChars(A2)

		lea		ToGad(PC),A1
		lea		ToInfo(DB),A2
		move.l		A2,gg_SpecialInfo(A1)
		lea		ToBuf(DB),A1
		move.l		A1,si_Buffer(A2)
		move.w		#11,si_MaxChars(A2)

		Prepare		Exec_Call
		suba.l		A1,A1
		CallLib		FindTask		; Find us
		movea.l		D0,A2
		tst.l		pr_CLI(A2)
		bne.S		GetLibs
		lea		pr_MsgPort(A2),A0
		CallLib		WaitPort		; wait for a message
		lea		pr_MsgPort(A2),A0
		CallLib		GetMsg			; then get it
		move.l		D0,WBenchMsg(DB)	; save it for later reply
GetLibs		lea		IntuiName(PC),A1
		CallLib		OldOpenLibrary
		move.l		D0,IntuiBase(DB)
		beq.S		Error

		Prepare		Intuition_Call
		lea		NW(PC),A0
		CallLib		OpenWindow
		move.l		D0,DWindow(DB)
		movea.l		D0,A0
		beq.S		Error
		move.l		wd_RPort(A0),Rp(DB)
		move.l		wd_UserPort(A0),Up(DB)
		lea		WinTitle(PC),A1
		lea		ScrTitle(PC),A2
		CallLib		SetWindowTitles
		bra.S		Main

Error
Exit
FreeWindow	Prepare		Intuition_Call
		move.l		DWindow(DB),D0
		beq.S		FreeIntui
		move.l		D0,A0
		CallLib		CloseWindow
FreeIntui	Prepare		Exec_Call
		move.l		IntuiBase(DB),D0
		beq.S		ReplyWB
		movea.l		D0,A1
		CallLib		CloseLibrary
ReplyWB		move.l		WBenchMsg(DB),D2
		beq.S		AllDone
		CallLib		Forbid
		movea.l		D2,A1
		CallLib		ReplyMsg		; Reply WBenchMessage if we are started from WB
AllDone		dcFree
		moveq		#0,D0
DoNothing	rts


Main
EventLoop	movea.l		Up(DB),A0
		Prepare		Exec_Call
		CallLib		WaitPort
GetNextMsg	Call		GetAMessage
		beq.S		EventLoop
		move.l		Class(DB),D0
		cmp.l		#CLOSEWINDOW,D0
		beq.S		Exit
		andi.w		#GADGETDOWN+GADGETUP,D0
		bne.S		GJ
		cmp.l		#ACTIVEWINDOW,D0
		bne.S		GetNextMsg
		Call		ActivateFrom
		bra.S		GetNextMsg
GJ		movea.l		IAddress(DB),A1
		move.w		gg_GadgetID(A1),D0	; GadgetID is offset from GJ
		jsr		GJ(PC,D0.W)
		bra.S		GetNextMsg

*»»» User pressed RETURN in the 'To' string-gadget,
*»»» or activated the window, or an error was found
*»»» in the 'From' string-gadget.
ActivateFrom	lea		FromGad(PC),A0
		bra.S		ActivateStr
*»»» User pressed RETURN in the 'From' string-gadget,
*»»» or an error was found in the 'To' string-gadget.
ActivateTo	lea		ToGad(PC),A0
ActivateStr	Prepare		Intuition_Call
		move.l		DWindow(DB),A1
		suba.l		A2,A2
		CallLib		ActivateGadget
		rts

*»»» User clicked the 'Solve' button
DoSolve		lea		FromBuf(DB),A0
		Call		ParseDate
		bmi.S		1$
		move.l		D1,D4
		move.l		D2,D5
		move.l		D3,D6
		lea		ToBuf(DB),A0
		Call		ParseDate
		bmi.S		2$
		exg		D1,D4
		exg		D2,D5
		exg		D3,D6
		move.l		D3,D0
		swap		D0
		move.w		D2,D0
		lsl.w		#8,D0
		move.b		D1,D0
		move.l		D6,D7
		swap		D7
		move.w		D5,D7
		lsl.w		#8,D7
		move.b		D4,D7
		cmp.l		D0,D7		; Compare date order
		blt.S		1$
		Call		CalcDays
		lea		TxtAre+6(PC),A0
		Call		MakeDecStr
		Call		PrintSolution
		Call		ActivateFrom
		rts
1$		Call		ActivateFrom
		bra.S		3$
2$		Call		ActivateTo
3$		Prepare		Intuition_Call
		move.l		DWindow(DB),A0
		move.l		wd_WScreen(A0),A0
		CallLib		DisplayBeep
		lea		TxtAre+6(PC),A0
		moveq		#8,D0
4$		move.b		#'?',(A0)+
		dbf		D0,4$
		Call		PrintSolution
		rts

PrintSolution	Prepare		Intuition_Call
		move.l		Rp(DB),A0
		lea		ITxtAre(PC),A1
		move.w		#Sx,D0
		moveq		#Sy,D1
		CallLib		PrintIText
		rts

*»»» Call:	D1 = Day	(from)
*»»»		D2 = Month	(from)
*»»»		D3 = Year	(from)
*»»»		D4 = Day	(to)
*»»»		D5 = Month	(to)
*»»»		D6 = Year	(to)
CalcDays	Push		D1-D7/A0
		moveq		#0,D7
		move.w		D3,D0
		Call		AdjustYear		
		lea		Days-1(PC),A0
		add.w		D2,A0
		move.b		(A0)+,D7
		sub.w		D1,D7
		add.w		D4,D7
		sub.w		D3,D6
		subq.w		#1,D6
		bge.S		1$
		sub.w		D2,D5
		bgt.S		6$
		move.w		D4,D7
		sub.w		D1,D7
		bra.S		9$
1$		neg.w		D2
		add.w		#12,D2
		bra.S		3$
2$		moveq		#0,D0
		move.b		(A0)+,D0
		add.l		D0,D7
3$		dbf		D2,2$
		bra.S		5$
4$		add.l		#365-28,D7
		moveq		#0,D0
		move.b		Days+1(PC),D0
		add.l		D0,D7
5$		addq.w		#1,D3
		move.w		D3,D0
		Call		AdjustYear		
		dbf		D6,4$
		lea		Days(PC),A0
6$		subq.w		#1,D5
		bra.S		8$
7$		moveq		#0,D0
		move.b		(A0)+,D0
		add.l		D0,D7
8$		dbf		D5,7$
9$		move.l		D7,D0
		Pop		D1-D7/A0
		rts

*»»» Call:	D0 = year to adjust
*»»» Changes the number of days in the month of February
*»»» according to the rules for leapyear.
AdjustYear	Push		D0-D1/A0
		ext.l		D0
		move.l		D0,D1
		andi.w		#%11,D1			;Year%4
		bne.S		1$
		move.l		D0,D1
		divu		#400,D1			;Year%400
		swap		D1
		tst.w		D1
		beq.S		2$
		move.l		D0,D1
		divu		#100,D1
		swap		D1			;Year%100
		tst.w		D1
		bne.S		2$
1$		moveq		#28,D0
		bra.S		3$
2$		moveq		#29,D0			;If ((Year%400==0)||((Year%100!=0)&&(Year%4==0)))
3$		lea		Days+1(PC),A0
		move.b		D0,(A0)			;Days[1]=28 or Days[1]=28
		Pop		D0-D1/A0
		rts

*»»» Call:	A0 = String
ParseDate	Call		DoNumber
		bne.S		1$
		move.l		D0,D1		; Day
		Call		DoNumber
		bne.S		1$
		move.l		D0,D2		; Month
		Call		DoNumber
		bmi.S		1$
		beq.S		1$
		move.l		D0,D3		; Year
		Call		AdjustYear	; Check for valid date
		tst.l		D2
		ble.S		1$
		cmp.w		#12,D2
		bgt.S		1$
		tst.l		D1		; Month was valid
		ble.S		1$
		lea		Days(PC),A0
		cmp.b		-1(A0,D2),D1
		bgt.S		1$
		moveq		#0,D0		; And day was valid too
		rts
1$		moveq		#-1,D0
		rts

*»»» Call:	A0 = String
DoNumber	Push		D1
		moveq		#0,D0
1$		move.b		(A0)+,D1
		beq.S		6$
		cmp.b		#'-',D1
		beq.S		5$
		sub.b		#'0',D1
		blt.S		4$
		cmp.b		#9,D1
		bgt.S		4$
		mulu		#10,D0
		ext.w		D1
		add.w		D1,D0
		bra.S		1$
4$		moveq		#-1,D1
		bra.S		3$
6$		moveq		#1,D1
		bra.S		3$
5$		moveq		#0,D1
3$		Pop		D1
		rts

*»»» Call:	D0 = Number to convert to ascii
*»»»		A0 = Where to put string
MakeDecStr	Push		D1-D5/A0
		moveq		#9,D1
		tst.l		D0
		beq.S		6$
		subq.l		#1,D1
		asl.l		#2,D1
		moveq		#' ',D4
		moveq		#'0',D2
1$		move.w		D2,D3
		move.l		9$(PC,D1.l),D5
2$		cmp.l		D5,D0
		blt.S		3$
		addq.w		#1,D3
		sub.l		D5,D0
		bra.S		2$
3$		cmp.b		D2,D3
		bne.S		4$
		move.w		D4,D3
		bra.S		5$
4$		move.w		D2,D4
5$		move.b		D3,(A0)+
		subq.w		#4,D1
		bge.S		1$
		bra.S		8$
6$		subq.l		#2,D1
7$		move.b		#' ',(A0)+
		dbf		D1,7$
		move.b		#'0',(A0)+
8$		Pop		D1-D5/A0
		rts
9$		dc.l		1,10,100,1000,10000,100000,1000000,10000000

GetAMessage	Push		D0-D1/A0-A1/A6
		movea.l		Up(DB),A0
		Prepare		Exec_Call
		CallLib		GetMsg
		tst.l		D0
		beq.S		1$
		movea.l		D0,A1
		move.l		20(A1),Class(DB)
		move.l		28(A1),IAddress(DB)
		CallLib		ReplyMsg
		moveq		#1,D0
1$		Pop		D0-D1/A0-A1/A6
		rts

Days		dc.b		31,28,31,30,31,30,31,31,30,31,30,31

IntuiName	dc.b		'intuition.library',0
		EVEN

IDCMPFlags	=GADGETUP+GADGETDOWN+CLOSEWINDOW+ACTIVEWINDOW
OtherFlags	=WINDOWCLOSE+WINDOWDRAG+WINDOWDEPTH+NOCAREREFRESH+ACTIVATE
NW		dc.w		320-WW/2,128-WH/2,WW,WH
		dc.b		0,1
		dc.l		IDCMPFlags,OtherFlags
		dc.l		GadgetList,0,0,0,0
		dc.w		0,0,0,0,WBENCHSCREEN

WW		=222		; window width
WH		=78		; window height
SW		=53		; gadget width
SH		=21		; gadget height
Sx		=157		; gadget xpos
Sy		=34		; gadget ypos
FW		=88		; gadget width
FH		=10		; gadget height

GadgetList
FromGad		Gadget		ToGad,52,33,FW,FH,GADGHCOMP,RELVERIFY,STRGADGET
		Gadget2		FBorder,0,ITxtFrom,0,0,ActivateTo-GJ,0
ToGad		Gadget		SolveGad,52,48,FW,FH,GADGHCOMP,RELVERIFY,STRGADGET
		Gadget2		FBorder,0,ITxtTo,0,0,ActivateFrom-GJ,0
SolveGad	Gadget		0,Sx,Sy,SW,SH,GADGHCOMP,RELVERIFY,BOOLGADGET
		Gadget2		ButBorder,0,ITxtSolve,0,0,DoSolve-GJ,0

ButBorder	Border		-2,-1,1,0,1,9,ButVectors,But2Border
ButVectors	dc.w		2,0,SW+1,0,SW+3,2,SW+3,SH-1,SW+1,SH+1,2,SH+1,0,SH-1,0,2,2,0
But2Border	Border		-107,37,1,0,1,2,FVectors,0
FBorder		Border		0,8,1,0,1,2,FVectors,0
FVectors	dc.w		0,0,FW-1,0

ITxtSolve	IntuiText	3,0,1,6,7,TxtSolve,ITxtAre
ITxtAre		IntuiText	1,0,1,-147,29,TxtAre,ITxtFormat
ITxtFormat	IntuiText	1,0,1,-148,-16,TxtFormat,0
ITxtFrom	IntuiText	1,0,1,-43,0,TxtFrom,0
ITxtTo		IntuiText	1,0,1,-43,0,TxtTo,0

TxtSolve	dc.b		'Solve',0
TxtAre		dc.b		'are   ?????????   days',0
TxtFormat	dc.b		'Date-format is DD-MM-YYYY',0
TxtFrom		dc.b		'From',0
TxtTo		dc.b		'to',0
WinTitle	dc.b		'Day2Day V1.0',0
ScrTitle	dc.b		'Day2Day V1.0 © 1991 by Preben Nielsen',0
		EVEN

TxtAttr		dc.l		FontName
		dc.w		TOPAZ_EIGHTY
		dc.b		FS_NORMAL,FPB_ROMFONT
FontName	dc.b		'topaz.font',0
		END

