;********************************************************************
;
; cookie
;
; (C) Stuart Mitchell - 11/11/90
;
;********************************************************************

		section cookie,code

		opt o+

		incdir	include:

		include exec/types.i
		include exec/memory.i
		include libraries/dos.i
		include libraries/arpbase.i
		include libraries/dosextens.i

_LVOOpenLibrary equ	-$228
_LVOCloseLibrary equ	-$19e

BUFFER		equ	256
COOKIE		equ	1024		; size of buffer to store cookie
SEPERATOR	equ	$0c		; char that seperates fortunes

; register defns. - NB don't change address-->data or vice versa

r_jar		equr	a2
r_buffer	equr	a3
r_dest		equr	a4
r_arpbase	equr	a6	; this must be a6

r_cookies_fh	equr	d4
r_ptrs_fh	equr	d5
r_current_char	equr	d6
r_num_read	equr	d7

CALL		macro
		jsr	_LVO\1(a6)
		endm

;********************************************************************

start:          lea	arplib(pc),a1
		moveq.l	#0,d0
		move.l	4.w,a6
		CALL	OpenLibrary
		tst.l	d0
		beq	to_dos
		move.l	d0,r_arpbase

; allocate memory (MEMF_PUBLIC|MEMF_CLEAR) for cookie & file buffer

		move.l	#BUFFER+COOKIE,d0
		CALL	ArpAlloc
		tst.l	d0
		beq	closearp

cont:		move.l	d0,r_jar		; save address of cookie jar
		lea	COOKIE(r_jar),r_buffer  ; address of read buffer

; open cookie/pointers file

		move.l	#file,d1
		move.l	#MODE_OLDFILE,d2
		CALL	ArpOpen 		; open cookies
		move.l	d0,r_cookies_fh		; sets zero flag if zero
		beq.s	error
		move.l	#ptrs,d1
		CALL	ArpOpen 		; open pointers
		move.l	d0,r_ptrs_fh
		bne.s	setseed 		; ok ... so continue

; if error then print msg

error:		lea	no_cookies(pc),a1
		CALL	Puts
		bra.s	closearp

; main loop proggy

setseed:	move.l	r_buffer,d1		; move start of buffer
		CALL	DateStamp

;set random seed based on ticks value from DateStamp

		move.l	ds_Tick(r_buffer),d0
		bsr	RandomSeed

; get position in file

getpos: 	moveq.l	#0,d2
		move.l	r_ptrs_fh,d1
		moveq.l #OFFSET_BEGINNING,d3
		CALL	Seek			; move to start pointers

; get number of cookies

		bsr.s	readptr

; generate random number in range 0..(number cookies -1)

		move.l	(r_buffer),d0
		bsr	Random			; get number 0..number cookies

		asl.l	#2,d0			; times 4
		move.l	d0,d2
		move.l	r_ptrs_fh,d1
		moveq.l #OFFSET_CURRENT,d3
		CALL	Seek			; move to cookie pointer
		bmi.s	getpos

		bsr.s	readptr
		move.l	(r_buffer),d2           ; save cookie position

; seek to position in cookie file

		move.l	r_cookies_fh,d1		; get cookie file handle
		moveq.l #OFFSET_BEGINNING,d3
		CALL	Seek
		bmi.s	getpos			; if negative repeat

; copy fortune into buffer

		moveq.l	#0,r_current_char
		moveq.l	#0,r_num_read
		move.l	r_jar,r_dest		; a4 = destination char

copy_fort:	bsr.s	getchar
		beq.s	out			; if EOF then print
		move.b	d0,(r_dest)+
		cmpi.b	#SEPERATOR,d0
		bne.s	copy_fort

out:		clr.b	-1(r_dest)              ; null terminate string

; write contents of cookie jar

		move.l	r_jar,a1
		CALL	Puts

; Arp automatically frees memory & closes files

closearp:	move.l	r_arpbase,a1
		move.l	4.w,a6
		CALL	CloseLibrary

to_dos: 	moveq.l	#0,d0
		rts

; read 4 bytes from file, used to get number of cookies/cookie locations

readptr:	move.l	r_ptrs_fh,d1
		moveq.l #4,d3
		move.l	r_buffer,d2
		jmp	_LVORead(a6)            ; read 4 bytes

; get character from file, refill buffer if required

getchar:	cmp.l	r_current_char,r_num_read
		bne.s	retchar
		move.l	r_cookies_fh,d1
		move.l	r_buffer,d2
		move.l	#BUFFER,d3
		CALL	Read
		move.l	d0,r_num_read
		beq.s	oh_no			; read failed!
		moveq.l #0,r_current_char
retchar:	move.b	(r_buffer,r_current_char),d0
		addq.l	#1,r_current_char
oh_no:		rts

; random number functions

; The following code was taken from a public domain program. However I
;have since forgetton the name of the author. I apologise to him/her but
;do acknowledge their authorship.

RandomSeed	add.l	d0,d1		user seed in d0 (d1 too)
		movem.l d0/d1,rnd

LongRnd 	movem.l d2-d3,-(sp)
		movem.l rnd,d0/d1	d0=LSB's, d1=MSB's of random number
		andi.b	#$0e,d0 	ensure upper 59 bits are an...
		ori.b	#$20,d0 	...odd binary number
		move.l	d0,d2
		move.l	d1,d3
		add.l	d2,d2		accounts for 1 of 17 left shifts
		addx.l	d3,d3		[d2/d3] = rnd*2
		add.l	d2,d0
		addx.l	d3,d1		[d0/d1] = rnd*3
		swap	d3		shift [d2/d3] additional 16 times
		swap	d2
		move.w	d2,d3
		clr.w	d2
		add.l	d2,d0		add to [d0/d1]
		addx.l	d3,d1
		movem.l d0/d1,rnd	save for next time through
		move.l	d1,d0		most random part to d0
		movem.l (sp)+,d2-d3
		rts

Random		move.w	d2,-(sp)
		move.w	d0,d2		save upper limit
		beq.s	10$		range of 0 returns 0 always
		bsr.s	LongRnd 	get a longword random number
		clr.w	d0		use upper word (it's most random)
		swap	d0
		divu.w	d2,d0		divide by range...
		clr.w	d0		...and use remainder for the value
		swap	d0		result in d0.w
10$		move.w	(sp)+,d2
		rts

		even
no_cookies:	dc.b	"No cookies!",$0a,0
		even
file:		dc.b	"s:cookie.dat",0
		even
ptrs:		dc.b	"s:cookie.ptr",0
		even
arplib: 	dc.b	"arp.library",0
		even
rnd		ds.l	2		random number

		end
