
	incdir	Includes:
	include	libraries/dosextens.i
	include	offsets/dos_lib.i
	include	offsets/exec_lib.i


TRUE		equ	1
FALSE		equ	0

KICKVERSION	equ	36

DATE_MAX	equ	10		;maksymalna dlugosc
YEAR_MAX	equ	2899		;maksymalne wartosci
MONTH_MAX	equ	12		;
DAY31_MAX	equ	31
DAY30_MAX	equ	30
DAY28_MAX	equ	28
DAY29_MAX	equ	29
M31_MAX		equ	7		;siodmy miesiac
WEEK_MAX	equ	7		;tyle dni w tygodniu

YEAR_1582	equ	1582
MONTH_1582	equ	10
DAY_1582	equ	15

FEBRUARY	equ	2
FEB_MASK	equ	$00000003	;zostawiam ostatnie dwa bity

STO		equ	100
CZTERYSTA	equ	400		;


	section	Date2Day,code

Begin:
	bra	Start			;omijam version string

VerStr:
	dc.b	"$VER: Date2Day v1.2 (08.12.96)",0

Author:
	dc.b	'© 1996 by Tadek Knapik. Public Domain.',0

Start:
	move.l	$4,_SysBase

;na wypadek uruchomienia spod Workbencha

	move.l	_SysBase,a6		;execbase
	sub.l	a1,a1			;nazwa tasku do szukania
	jsr	_LVOFindTask(a6)	;szukam tego tasku
	move.l	d0,a0			;there it is
	tst.l	pr_CLI(a0)		;czy task spod CLI
	bne	CLIStuff		;tak!
	lea	pr_MsgPort(a0),a0	;adres portu
	move.l	a0,a2			;"zapamietuje"
	jsr	_LVOWaitPort(a6)	;czekam na message od WB
	move.l	a2,a0			;adres portu
	jsr	_LVOGetMsg(a6)		;pobranie
	move.l	d0,a1			;do a1
	jsr	_LVOForbid(a6)		;wstrzymanie multitaskingu
	jsr	_LVOReplyMsg(a6)	;oddanie message do Workbencha
	move.l	#10,d0			;return code
	rts

CLIStuff:
	move.l	_SysBase,a6		;exec
	bsr	OpenDOS			;otwarcie dos.library
	beq	NoDOS			;brak?


	move.l	_DOSBase,a6		;spwrawdzmy, czy mamy
	jsr	_LVOOutput(a6)		;gdzie wyslac
	move.l	d0,Output		;informacje
	beq	NoArgs			;nie?!?

	move.l	#0,Date			;prepare

	move.l	#Template,d1		;template
	move.l	#ArgsArray,d2		;array
	moveq	#0,d3			;no struct
	jsr	_LVOReadArgs(a6)	;take it
	move.l	d0,_ReadArgs
	beq	Info

	move.l	Date,a1			;adres daty	
	bsr	CountString		;czy aby nie za dluga?
	cmpi.l	#DATE_MAX,d0		;zobaczmy
	bgt	BadArgs

	move.l	a1,a0
	bsr	ParseDate
	beq	BadArgs

	bsr	ParseTheDate
	beq	BadArgs

	cmpi.l	#WEEK_MAX,d0
	bgt	BadArgs

	moveq	#0,d3			;
	mulu	#4,d0			;na longwordy

	lea	DayNames,a0
	move.l	(a0,d0.l),a0		;adres nazwy dnia
	move.b	(a0)+,d3		;dlugosc
	move.l	a0,d2			;bufor
	move.l	Output,d1		;stdout
	move.l	_DOSBase,a6
	jsr	_LVOWrite(a6)

	bsr	FreeArgs

Koniec:
	bsr	CloseDOS
	moveq	#0,d0
	rts



BadArgs:
	bsr	ShowBadArgs
	bsr	FreeArgs
NoArgs:
	bsr	CloseDOS
NoDOS:
	moveq	#10,d0			;return code
	rts



ShowBadArgs:
	move.l	_DOSBase,a6
	lea	BadArgsTxt,a0
	moveq	#0,d3
	move.b	(a0)+,d3
	move.l	a0,d2
	move.l	Output,d1
	jsr	_LVOWrite(a6)
	rts

Info:
	move.l	_DOSBase,a6
	lea	InfoTxt,a0
	moveq	#0,d3
	move.b	(a0)+,d3
	move.l	a0,d2
	move.l	Output,d1
	jsr	_LVOWrite(a6)
	bra	Koniec


;ponizsza bycza procedura zwraca w d0 blad (0) lub numer dnia tygodnia

ParseTheDate:

;teraz do roboty. Najpierw nalezy podzielic rok na stulecia i reszte

	move.l	Year,d0
	moveq	#0,d5
	moveq	#0,d6
	moveq	#0,d7
	divu	#STO,d0
	move.w	d0,d5			;stulecia do d5
	swap	d0
	move.w	d0,d6			;reszta do d6	

	move.l	Year,d3			;jesli rok podzielny
	divu	#CZTERYSTA,d3		;przez 400, to jest
	swap	d3			;przestepny
	tst.w	d3			;
	beq	LeapYear		;OK

	move.l	d6,d3			;sprawdzam, jesli zerowy, a nie
	beq	TestCalendar		;podzielny przez 400, to normalny

	andi.l	#FEB_MASK,d3		;moze przestepny?
	bne	TestCalendar		;(podzielny przez 4)

LeapYear:
	moveq	#1,d7			;d7 - znacznik przestepczosci :-)


TestCalendar:

;jezeli jest to przed 15.10.1582, to kalendarz julianski

	cmpi.l	#YEAR_1582,Year
	bgt	OurCalendar
	blt	Julian

;rok 1582

	cmpi.l	#MONTH_1582,Month
	bgt	OurCalendar
	blt	Julian

;miesiac pazdziernik

	cmpi.l	#DAY_1582,Day
	bge	OurCalendar		;tego dnia juz gregorianski

Julian:
	moveq	#0,d3
	move.l	d5,d2			;stulecia (wieki)
	divu	#7,d2			;przez 7
	swap	d2			;
	move.w	d2,d3			;reszta w d3 - wskaznik wieku
	bra	TakeYear


OurCalendar:

	move.l	#0,d3			;wskaznik

	cmpi.l	#17,d5
	beq	TakeYear
	cmpi.l	#21,d5
	beq	TakeYear
	cmpi.l	#25,d5
	beq	TakeYear

	move.l	#2,d3			;

	cmpi.l	#18,d5
	beq	TakeYear
	cmpi.l	#22,d5
	beq	TakeYear
	cmpi.l	#26,d5
	beq	TakeYear

	move.l	#4,d3

	cmpi.l	#15,d5
	beq	TakeYear
	cmpi.l	#19,d5
	beq	TakeYear
	cmpi.l	#23,d5
	beq	TakeYear
	cmpi.l	#27,d5
	beq	TakeYear

	move.l	#5,d3

	cmpi.l	#16,d5
	beq	TakeYear
	cmpi.l	#20,d5
	beq	TakeYear
	cmpi.l	#24,d5
	beq	TakeYear
	cmpi.l	#28,d5
	beq	TakeYear

	bra	BadData


;teraz w d3 mam wskaznik stulecia, ktory przeksztalcam na wskaznik
;tablicy i pobieram numerek.

TakeYear:

	mulu	#4,d3		;wskaznik x4 (bo longwordy)
	lea	YearTable,a0
	move.l	(a0,d3.l),a0	;konkretna tablica

;teraz w a0 mam adres tablicy. Mam z niej odczytac cyfre, ktorej offset
;biore z roku..

	moveq	#0,d2
	moveq	#0,d3
	move.l	d6,d1		;lata
	move.l	d1,d3		;tu tez
	divu	#4,d1		;bo przestepne
	move.w	d1,d2		;ilosc przestepnych
	add.l	d2,d3		;dodaje do aktualnych
	moveq	#0,d1
	moveq	#0,d2
	divu	#7,d3		;dziele przez 7 (bo tyle tabelek)
	swap	d3		;biore reszte
	move.w	d3,d2		;teraz mam offset!

	moveq	#0,d0
	move.b	(a0,d2.l),d0	;mam tego bajta!

;w d0 mam teraz offset do odczytu z tabelek miesiecy. Sprawdzam wiec
;miesiace

	cmpi.l	#1,Month
	bne	TakeFebruary

	tst.l	d7
	beq	TakeUsualJanuary

	lea	MTable5,a0
	bra	TakeAMonth

TakeUsualJanuary:
	lea	MTable6,a0
	bra	TakeAMonth

TakeFebruary:
	cmpi.l	#2,Month
	bne	TakeMarch

	tst.l	d7
	beq	TakeUsualFebruary

	lea	MTable1,a0
	bra	TakeAMonth

TakeUsualFebruary:
	lea	MTable2,a0
	bra	TakeAMonth

TakeMarch:
	cmpi.l	#3,Month
	bne	TakeApril

	lea	MTable2,a0
	bra	TakeAMonth

TakeApril:
	cmpi.l	#4,Month
	bne	TakeMay

	lea	MTable5,a0
	bra	TakeAMonth

TakeMay:
	cmpi.l	#5,Month
	bne	TakeJune

	lea	MTable0,a0
	bra	TakeAMonth

TakeJune:
	cmpi.l	#6,Month
	bne	TakeJuly

	lea	MTable3,a0
	bra	TakeAMonth

TakeJuly:
	cmpi.l	#7,Month
	bne	TakeAugust

	lea	MTable5,a0
	bra	TakeAMonth

TakeAugust:
	cmpi.l	#8,Month
	bne	TakeSeptember

	lea	MTable1,a0
	bra	TakeAMonth

TakeSeptember:
	cmpi.l	#9,Month
	bne	TakeOctober

	lea	MTable4,a0
	bra	TakeAMonth

TakeOctober:
	cmpi.l	#10,Month
	bne	TakeNovember

	lea	MTable6,a0
	bra	TakeAMonth

TakeNovember:
	cmpi.l	#11,Month
	bne	TakeDecember

	lea	MTable2,a0
	bra	TakeAMonth

TakeDecember:
	cmpi.l	#12,Month
	bne	BadData

	lea	MTable4,a0

;teraz mam w a0 odpowiednia tablice dla miesiaca. W d0 ciagle offset.

TakeAMonth:
	moveq	#0,d1
	move.b	(a0,d0.l),d1	;kopiuje wskaznik

;teraz musze tylko wczytac adres poprawnej tablicy dla dnia

	moveq	#0,d0
	moveq	#0,d2
	moveq	#0,d3
	move.l	Day,d2
	divu	#7,d2		;dziele przez 7 (liczba tabelek)
	swap	d2		;biore reszte, i odejmuje od niej
	move.w	d2,d3		;jeden (bo dni miesiaca zaczynaja sie
	tst.l	d3		;od 1, chyba ze jest to zero - wtedy
	beq	DayZero		;zmieniam na 6)
	subq.l	#1,d3		;
	bra	TakeADay

DayZero:
	move.l	#6,d3		;offset

TakeADay:
	mulu	#4,d3		;na wskaznik longwordow

	lea	DayTable,a0	;tablica tablic
	move.l	(a0,d3.l),a0	;odpowiednia tablica

;w d1 ciagle wskaznik wziety z miesiaca..

	move.b	(a0,d1.l),d0	;numer dnia
	rts			;koniec!



BadData:
	move.l	#FALSE,d0
	rts




;kopiowanie

ParseDate:
	tst.b	(a0)
	beq	ParseBad

	lea	DayBuffer,a1
ParseDay:
	move.b	(a0)+,(a1)+	;kopiowanie dnia
	cmpi.b	#'.',(a0)
	beq	DayParsed
	cmpi.b	#'-',(a0)
	beq	DayParsed
	cmpi.b	#' ',(a0)
	beq	DayParsed
	tst.b	(a0)
	beq	ParseBad
	bra	ParseDay

DayParsed:
	move.b	#0,(a1)		;zakonczenie zerem
	adda.l	#1,a0
	tst.b	(a0)
	beq	ParseBad
	lea	MonthBuffer,a1

ParseMonth:
	move.b	(a0)+,(a1)+	;kopiowanie miesiaca
	cmpi.b	#'.',(a0)
	beq	MonthParsed
	cmpi.b	#'-',(a0)
	beq	MonthParsed
	cmpi.b	#' ',(a0)
	beq	MonthParsed
	tst.b	(a0)
	beq	ParseBad
	bra	ParseMonth

MonthParsed:
	move.b	#0,(a1)		;zakonczenie zerem
	adda.l	#1,a0
	tst.b	(a0)
	beq	ParseBad
	lea	YearBuffer,a1

ParseYear:
	move.b	(a0)+,(a1)+	;kopiowanie roku
	cmpi.b	#'.',(a0)
	beq	YearParsed
	cmpi.b	#'-',(a0)
	beq	YearParsed
	cmpi.b	#' ',(a0)
	beq	YearParsed
	tst.b	(a0)
	beq	YearParsed
	bra	ParseYear

YearParsed:
	move.b	#0,(a1)		;zakonczenie zerem

	move.l	_DOSBase,a6
	lea	DayBuffer,a1
	move.l	a1,d1			;bufor z cyframi
	lea	Day,a2
	move.l	a2,d2			;long na dzien
	jsr	_LVOStrToLong(a6)	;konwersja
	tst.l	d0
	bmi	ParseBad

	lea	MonthBuffer,a1
	move.l	a1,d1			;bufor z cyframi
	lea	Month,a2
	move.l	a2,d2			;long na miesiac
	jsr	_LVOStrToLong(a6)	;konwersja
	tst.l	d0
	bmi	ParseBad

	lea	YearBuffer,a1
	move.l	a1,d1			;bufor z cyframi
	lea	Year,a2
	move.l	a2,d2			;long na rok
	jsr	_LVOStrToLong(a6)	;konwersja
	tst.l	d0
	bmi	ParseBad


;teraz mam podane wartosci. Pozostaje sprawdzic, czy nie sa one
;niewlasciwe

	cmpi.l	#YEAR_MAX,Year
	bgt	ParseBad

	cmpi.l	#MONTH_MAX,Month
	bgt	ParseBad
	tst.l	Month
	beq	ParseBad

	tst.l	Day
	beq	ParseBad

	cmpi.l	#FEBRUARY,Month
	bne	CheckDay

;sprawdzanie dni dla lutego


	move.l	Year,d0			;pelny rok
	moveq	#0,d1			;clean
	divu	#STO,d0			;odrzucam stulecia
	swap	d0			;reszta do mlodszego slowa
	move.w	d0,d1			;

	move.l	d1,d3			;jesli podzielny
	divu	#CZTERYSTA,d3		;przez 400, to jest
	swap	d3			;przestepny
	tst.w	d3			;
	beq	TestedLeapYear		;OK

	tst.l	d1
	beq	UsualFebruary		;rok 0

	andi.l	#FEB_MASK,d1		;podzielny przez 4 (przestepny?)
	bne	UsualFebruary		;nie

;rok przestepny (nie zerowy, podzielny przez 4)

TestedLeapYear:
	cmpi.l	#DAY29_MAX,Day
	bgt	ParseBad
	bra	ParseOver		;koniec sprawdzania

UsualFebruary:
	cmpi.l	#DAY28_MAX,Day
	bgt	ParseBad
	bra	ParseOver		;koniec sprawdzania


CheckDay:
	move.l	Month,d0		;miesiac
	cmpi.l	#M31_MAX,d0		;wiekszy od 7?
	ble	UsualMonth
	subq.l	#1,d0			;dla >7 zmiana

;dla nieparzystych - 31, dla parzystych - 30 (luty sprawdzony wczesniej)

UsualMonth:
	btst	#0,d0			;parzysty?
	beq	PMonth			;nooo..

	cmpi.l	#DAY31_MAX,Day
	bgt	ParseBad
	bra	ParseOver

PMonth:
	cmpi.l	#DAY30_MAX,Day
	bgt	ParseBad

ParseOver:
	move.l	#TRUE,d0		;OK
	rts

ParseBad:
	move.l	#FALSE,d0
	rts


;argument w a1

CountString:				;zlicza dlugosc (bez zera)
	move.l	a1,a0
	moveq	#0,d0
CountLoop:
	cmpi.b	#0,(a0)			;zakonczenie zerem lub
	beq	Counted			;tez
	cmpi.b	#10,(a0)		;koncem linii
	beq	Terminated		;
	adda.l	#1,a0			;nastepny znak
	addq.l	#1,d0			;licznik
	bra	CountLoop

Terminated:
	move.b	#0,(a0)
Counted:
	rts

FreeArgs:
	move.l	_DOSBase,a6
	move.l	_ReadArgs,d1
	jsr	_LVOFreeArgs(a6)
	rts



OpenDOS:
	lea	DosName,a1		;nazwa
	move.l	#KICKVERSION,d0
	jsr	_LVOOpenLibrary(a6)	;otwarcie
	move.l	d0,_DOSBase		;baza dos.library
	rts

CloseDOS:
	move.l	_DOSBase,a1		;baza dosu
	move.l	4,a6			;baza exec
	jsr	_LVOCloseLibrary(a6)	;zamkniecie dos.library
	rts



	section Date2Dayd,data


YearTable:
	dc.l	YTable0
	dc.l	YTable1
	dc.l	YTable2
	dc.l	YTable3
	dc.l	YTable4
	dc.l	YTable5
	dc.l	YTable6

YTable0:
	dc.b	6,0,1,2,3,4,5
YTable1:
	dc.b	5,6,0,1,2,3,4
YTable2:
	dc.b	4,5,6,0,1,2,3
YTable3:
	dc.b	3,4,5,6,0,1,2
YTable4:
	dc.b	2,3,4,5,6,0,1
YTable5:
	dc.b	1,2,3,4,5,6,0
YTable6:
	dc.b	0,1,2,3,4,5,6


;UWAGA! Zmiana w porownaniu do oryginalnej tabelki - zero zostalo
;przesuniete na pierwsza pozycje - offset!

MTable0:
	dc.b	1,2,3,4,5,6,0
MTable1:
	dc.b	2,3,4,5,6,0,1
MTable2:
	dc.b	3,4,5,6,0,1,2
MTable3:
	dc.b	4,5,6,0,1,2,3
MTable4:
	dc.b	5,6,0,1,2,3,4
MTable5:
	dc.b	6,0,1,2,3,4,5
MTable6:
	dc.b	0,1,2,3,4,5,6

DayTable:
	dc.l	DTable0
	dc.l	DTable1
	dc.l	DTable2
	dc.l	DTable3
	dc.l	DTable4
	dc.l	DTable5
	dc.l	DTable6

;UWAGA! Zmiana w porownaniu do oryginalnej tabelki - zero zostalo
;przesuniete na pierwsza pozycje - offset!
;dni zostaly przedstawione jako cyfry 1-7 (zero to blad zwracany przez
;ParseTheDate).


DTable0:
	dc.b	6,7,1,2,3,4,5
DTable1:
	dc.b	7,1,2,3,4,5,6
DTable2:
	dc.b	1,2,3,4,5,6,7
DTable3:
	dc.b	2,3,4,5,6,7,1
DTable4:
	dc.b	3,4,5,6,7,1,2
DTable5:
	dc.b	4,5,6,7,1,2,3
DTable6:
	dc.b	5,6,7,1,2,3,4
	dc.b	0

DayNames:
	dc.l	0			;zaczyna sie od 1, nie od 0..
	dc.l	Monday
	dc.l	Tuesday
	dc.l	Wednesday
	dc.l	Thursday
	dc.l	Friday
	dc.l	Saturday
	dc.l	Sunday


Monday:
	dc.b	7,'Monday',10
Tuesday:
	dc.b	8,'Tuesday',10
Wednesday:
	dc.b	10,'Wednesday',10
Thursday:
	dc.b	9,'Thursday',10
Friday:
	dc.b	7,'Friday',10
Saturday:
	dc.b	9,'Saturday',10
Sunday:
	dc.b	7,'Sunday',10
	dc.b	0

BadArgsTxt:
	dc.b	14,'Date invalid!',10,0

InfoTxt:
	dc.b	55,10,'Date2Day v1.2 by Tadek Knapik.',10
	dc.b	'Usage: d2d dd.mm.year',10,10,0

Template:
	dc.b	'DATE/A/F',0

DosName:
	dc.b	'dos.library',0


	section	Date2Dayb,bss

_SysBase:
	ds.l	1

_DOSBase:
	ds.l	1

_ReadArgs:
	ds.l	1

Output:
	ds.l	1

ArgsArray:
Date:
	ds.l	1

Day:
	ds.l	1

Month:
	ds.l	1

Year:
	ds.l	1

DayBuffer:
	ds.b	12

MonthBuffer:
	ds.b	12

YearBuffer:
	ds.b	12

