;--------------------------------------------------------------------
;  Module:     COOKIE.S
;
;  Abstract:   Everything you need for accessing the
;           cookie jar on Atari ST/TT computers.
;
;  Author:     Arnd Beissner, SciLab GmbH - Germany
;           Parts of the code are derived from Atari's
;           TOS 1.06 Release Notes.
;
;  Copyright:  COOKIE.S is in the public domain.
;
;  Compatibility:
;           Any ST/TT-compatible machine, any TOS version.
;
;  Language:   MAS68K by Borland
;
;  Version: 1.03
;
;  Date:    15.08.1991
;
;  History:
;
;  05.01.1991  AB - fixed a bug in CK_ReadJar
;
;  23.06.1991  AB  - added a copyright notice in the header
;
;  15.08.1991  AB  - Fixed an ugly bug in CK_ResizeJar. The bug
;                was most disastrous when no cookie jar was
;                present at all.
;
;--------------------------------------------------------------------
;  Comments:
;
;  Most functions in this module must be called in supervisor mode.
;  No registers except D0 (for the return value) are modified.
;--------------------------------------------------------------------

RESMAGIC        equ     $31415926

_p_cookies     equ      $5A0
_resvalid       equ     $426
_resvector      equ     $42a

;--------------------------------------------------------------------

      export   CK_JarInstalled
      export   CK_UsedEntries
      export   CK_JarSize
      export   CK_ResizeJar
      export   CK_ReadJar
      export   CK_WriteJar
      export   CK_SetOptions

      .text

;--------------------------------------------------------------------
; CK_JarInstalled
;
; See if the cookie jar is installed.
;
; Return value:
;     D0.L  = pointer to the cookie jar (0 = not installed)
;--------------------------------------------------------------------

CK_JarInstalled:
      move.l   _p_cookies,d0
      rts


;--------------------------------------------------------------------
; CK_UsedEntries
;
; Inquire the number of used cookie jar entries. The number includes
; the null cookie, so a return value of 0 means that there is no
; cookie jar at all.
;
; Return value:
;     D0.W = number of used cookie jar entries
;--------------------------------------------------------------------

CK_UsedEntries:
      move.l   a0,-(sp)
      move.l   _p_cookies,d0
      beq      _ue_end

      move.l   d0,a0
      clr.w d0
_ue_loop:
      addq.w   #1,d0
      tst.l (a0)
      beq      _ue_end
      addq.l   #8,a0
      bra      _ue_loop
_ue_end:
      move.l   (sp)+,a0
      rts


;--------------------------------------------------------------------
; CK_JarSize
;
; Inquire the total number of cookie jar entries.
;
; Return value:
;     D0.W = total number of cookie jar entries
;--------------------------------------------------------------------

CK_JarSize:
      move.l   a0,-(sp)
      move.l   _p_cookies,d0
      beq      _js_end

      move.l   d0,a0
_js_loop:
      tst.l (a0)
      beq      _js_found
      addq.l   #8,a0
      bra      _js_loop

_js_found:
      move.l   4(a0),d0
_js_end:
      move.l   (sp)+,a0
      rts


;--------------------------------------------------------------------
; CK_ResizeJar
;
; Resize the cookie jar to the desired size.
;
; Input arguments:
;     D0.W  = desired cookie jar size, number of entries
;
; Return value:
;     D0.W  = state (0=FALSE, 1=TRUE)
;--------------------------------------------------------------------

CK_ResizeJar:
      movem.l  d1-a6,-(sp)

      ; allocate a buffer for the new cookie jar
      andi.l   #$FFFF,d0
      move.l   d0,d7
      lsl.w #3,d0          ; 8 bytes per entry
      move.l   d0,-(sp)
      move.w   #$48,-(sp)        ; Malloc
      trap  #1
      addq.l   #6,sp
      tst.l d0             ; allocation successful?
      beq      _rj_end
      bpl      _rj_allocok
      clr.w d0
      bra      _rj_end

_rj_allocok:
      ; copy the contents of the old cookie jar to the new buffer
      move.l   d0,a2
      move.l   d0,a0
      move.l   _p_cookies,a1
      bsr      CK_UsedEntries
      bra      _rj_cpend
_rj_copy:
      move.l   (a1)+,(a0)+
      move.l   (a1)+,(a0)+
_rj_cpend:
      dbf      d0,_rj_copy

      ; insert the null cookie
      clr.l (a0)+          ; null cookie
      move.l   d7,(a0)           ; cookie jar size

      ; install the pointer to the new cookie jar
      move.l   a2,_p_cookies

      move.w   #1,d0          ; success

_rj_end:
      movem.l  (sp)+,d1-a6
      rts


;--------------------------------------------------------------------
; _instReset         **** internal ****
;
; Install a reset handler which clears the cookie jar on reboot.
; This is necessary for TOS versions before 1.06
;--------------------------------------------------------------------

_instReset:
      move.l   cookieJarXBRA,xbraId
      move.l   _resvalid,oldResValid
      move.l   #RESMAGIC,_resvalid
      move.l   _resvector,oldReset
      move.l   #newReset,_resvector
      rts

      dc.b  "XBRA"
xbraId:  dc.b  "ck01"            ; XBRA-structure
oldReset:
      dc.l    0
newReset:
      clr.l _p_cookies        ; clear the cookie jar
      move.l   oldReset,_resvector
      move.l   oldResValid,_resvalid
      jmp      (a6)


;--------------------------------------------------------------------
; _searchJar         **** internal ****
;
; search the position of the specified cookie
;
; Input arguments:
;     D0.L  = cookie name
;
; Return value:
;     D0.L  = pointer to cookie
;--------------------------------------------------------------------

_searchJar:
      movem.l  d2/a0,-(sp)
      move.l   d0,d2
      move.l   _p_cookies,d0
      beq      _search_end

      move.l   d0,a0
      clr.l d0
_search_next:
      tst.l (a0)        ; null cookie?
      beq      _search_end
      cmp.l (a0),d2        ; cookie found?
      beq      _search_found
      addq.l   #8,a0
      bra      _search_next

_search_found:
      move.l   a0,d0

_search_end:
      movem.l  (sp)+,d2/a0
      rts


;--------------------------------------------------------------------
; CK_ReadJar
;
; Read the value of the specified cookie.
;
; Input arguments:
;     D0.L  = cookie name
;     A0    = pointer to cookie value
;
; Return value:
;     D0.W  = state (0=FALSE, 1=TRUE)
;--------------------------------------------------------------------

CK_ReadJar:
      move.l   a1,-(sp)
      bsr      _searchJar        ; get a pointer to the jar entry
      tst.l d0
      beq      _ck_rdend         ; entry not found
      move.l   d0,a1
      move.l   4(a1),(a0)        ; read the cookie value
      move.w   #1,d0          ; success!

_ck_rdend:
      move.l   (sp)+,a1
      rts


;--------------------------------------------------------------------
; CK_WriteJar
;
; Insert a new entry into the cookie jar. If no cookie jar exists
; or the current cookie jar is full, a new, bigger cookie jar is
; installed. The increment in size can be set using CK_SetOptions.
;
; Input arguments:
;     D0.L  = cookie name
;     D1.L  = cookie value
;
; Return value:
;     D0.W  = state (0=FALSE, 1=TRUE)
;--------------------------------------------------------------------

CK_WriteJar:
      movem.l  d2-d3/a0,-(sp)

      move.l   d0,d2
      bsr      _searchJar
      tst.l d0
      bne      _ck_we_found

      ; cookie not found --> allocate one
      bsr      CK_JarSize
      move.w   d0,d3
      bsr      CK_UsedEntries
      sub.w d0,d3
      bgt      _ck_we_write

      ; no space for more cookies --> allocate a new cookie jar
      ; before that, install a reset function which resets the
      ; cookie jar on reboot. This is only necessary if no cookie
      ; jar exists.
      tst.l _p_cookies
      bne      _ck_we_inc
      bsr      _instReset

_ck_we_inc:
      add.w cookieJarIncrement,d0
      bsr      CK_ResizeJar
      tst.w d0
      beq      _ck_we_end                 ; allocation failed
      bsr      CK_UsedEntries

      ; write the cookie to location d0-1
_ck_we_write:
      subq.w   #1,d0
      lsl.w #3,d0
      move.l   _p_cookies,a0
      add.w d0,a0
      clr.l 8(a0)
      move.l   4(a0),12(a0)
      move.l   d2,(a0)
      move.l   d1,4(a0)
      bra      _ck_we_ok

_ck_we_found:
      ; cookie found --> overwrite with new value
      move.l   d0,a0
      move.l   d1,4(a0)

_ck_we_ok:
      move.w   #1,d0

_ck_we_end:
      movem.l  (sp)+,d2-d3/a0
      rts


;--------------------------------------------------------------------
; CK_SetOptions
;
; Set cookie jar options.
;
; Input arguments:
;     D0.W  = cookie jar increment when allocating a new buffer
;     D1.L  = xbra id for reset handler
;--------------------------------------------------------------------

CK_SetOptions:
      move.w   d0,cookieJarIncrement
      move.l   d1,cookieJarXBRA
      rts

;--------------------------------------------------------------------

      .data

cookieJarIncrement:
      dc.w  20

cookieJarXBRA:
      dc.b  'ck01'

;--------------------------------------------------------------------

      .bss

oldResValid:
      ds.l  1

      .end