; TagListLib is (c) by D. Pink
; TagListLib belongs to the TRITON conversion by Ph. Lonke
; but may be freely distributed and needs not to stay together
; with the TRITONBLITZ-Archive.
;
; v1.1 : Bugfixes and enhancements by Patrik Radman. (pradman@mail.abo.fi)
;
; Feel free to learn and/or to improve this library.
; Please keep the author up to date!
; I will if you tell me his e-mail address! ;-)  - PR
;
; Before compiling, remember to load "blitzlibs:libmacs.res".  - PR

#TagListLib=26     ; change 'xx' to a library id which fits in your system!

; #171 works for me, might fit your system too... No guarantees.  - PR

!libheader{#TagListLib,0,0,0,RunTimeErrs}

!afunction {#long}
!args
!libs {#TagListLib,#ua3}
!subs {_TagListAddr,0,0}
!args {#word}
!libs {#TagListLib,#ia3|#pd0}
!subs {_TagListAddr,0,0}
!name {"TagList","[#TagList] ;returns location of TagList, 0 if not in use",_toke}

!astatement
!args {#word,#long}
!libs {#TagListLib,#ia3|#pd0}
!subs {_InitTagList,0,0}
!name {"InitTagList","TagList#,NoTags.l"}

!astatement
!repargs {0,2,#long,#long}
!libs {#TagListLib,#ua3}
!subs {_AddTags,_AddTagsCheck,0}
!repargs {1,2,#word,#long,#long}
!libs {#TagListLib,#ia3|#pd0}
!subs {_AddTags,_AddTagsCheck,0}
!name {"AddTags","[#TagList] [[,Tag.l,Data.l]]"}

!afunction {#long}
!args
!libs {#TagListLib,#ua3}
!subs {_NoTagsLeft,0,0}
!args {#word}
!libs {#TagListLib,#ia3|#pd0}
!subs {_NoTagsLeft,0,0}
!name {"NoTagsLeft","[#TagList] ;returns the number of tags left in the taglist"}

_load:!nullsub{0,0,0}
_save:!nullsub{0,0,0}
_use:!nullsub{0,0,0}
_free:!nullsub{_FreeTagList,0,0}


; 5 is default maximum no of taglist
; 4 is size of object structure (2^4 = 16 bytes : SIZEOF .TagList = 12 bytes)
!libfin{_toke,_load,_save,_use,_free,5,4}

NEWTYPE .TagList
  TagListAddr.l
  TagListSize.l
  TagListPos.l
End NEWTYPE

; a3 points to the object.
; d1 number of tags
_InitTagList:
  ; Put the second parameter (no tags) on the stack
  MOVE.l d1,-(a7)
  ; Free any mem previously associated with this object
  BSR _FreeTagList
  ; Get the number of tags back off stack into d0
  MOVE.l (a7)+,d0

  ; If notags=0 then exit
  TST.l d0:BEQ size0

  ; Shift notags left 3 (same as *8), to calculate no bytes of mem needed
  ASL.l #3,d0
  ; Add 4 bytes to allow room for a 0 (taglists are null-terminated) at end
  ; Changed to 8 bytes because a tagitem always consists of a tag longword
  ; and a data longword.  - PR
  ADDQ #8,d0            ;;;; Changed PR 17.7.96  was: #4 ;;;;
  ; Set mem-type to 0 for allocmem (0=public-ram)
  ; Added $10000 which fills the allocated memory with zeroes.  - PR
  MOVE.l #$10000,d1     ;;;; Changed PR 17.7.96  was: MOVEQ #0 ;;;;
  ; Store the mem usuage in the object structure
  MOVE.l d0,4(a3)
  ; Call allocmem
  ALibJsr $c002
  ; d0 now contains address of mem.  Store in object as
  ; mem address and current position.
  MOVE.l d0,(a3)
  MOVE.l d0,8(a3)
size0:
RTS

_FreeTagList:
  ; a3 points to the object.  Move the mem address into d0
  ; and the size into d1
  MOVEM.l (a3),d0-d1
  ; Check if the mem address=0
  TST.l d0
  ; If =0 then no taglist associated with this object
  BEQ NoTagList
  ; Move mem address to a1 and size to d0 ready for call to freemem
  MOVE.l d0,a1
  MOVE.l d1,d0
  ; Call freemem
  ALibJsr $c003
  ; Set the address and size to zero to indicate none for this object
  MOVEQ.l #0,d0  ; do like this as shorter!!!
  MOVE.l d0,(a3)
  MOVE.l d0,4(a3)
NoTagList:
RTS

; a3 points to the object.
_TagListAddr
  ; move list address to d0
  MOVE.l(a3),d0
RTS

_AddTags
; d7 contains the no of parameters
; a3 contains the address of the object
; a2 contains address of start of parameters

; NOTE no error checking is done here!  If run-time errors
; are on then a run-time error is produced if there is not
; enough room in the taglist, but this check is avoided
; normally as this should not be a problem once the using
; program has been debugged!

  ; decrement no of parameters as loop goes from noparameters-1 downto 0
  SUBQ #1,d7
  ; Get current position into a0
  MOVE.l 8(a3),a0
Loop:
  ; Copy next taglist item (two longs) into mem, setting pointers
  ; to next position at the same time
  MOVE.l -(a2),(a0)+
  MOVE.l -(a2),(a0)+
  ; Decrement the counter, and branch if non-zero
  DBRA d7,Loop
  ; Move the new position into the taglist into the taglist structure
  MOVE.l a0,8(a3)
RTS


_NoTagsLeft
  ; Put taglist address into d0
  MOVE.l (a3),d0
  ; Add taglist size to address to find address of last tag
  ADD.l 4(a3),d0
  ; Find difference between address of last tag and current tag to
  ; find amount of tag mem left
  SUB.l 8(a3),d0
  ; Subtract 4 from val as last long doesn't count
  ; Changed to 8 bytes (last tagitem doesn't count)  - PR
  SUBQ #8,d0          ;;;; Changed PR 17.7.96  was: #4 ;;;;
  ; Shift right 3 places (/8) to convert no of bytes into no of tags
  ASR.l #3,d0
RTS

RunTimeErrs:

_AddTagsCheck:
  ; Find no of tags left
  JSR _NoTagsLeft
  ; Set d1 to 0 (Note, needed as want to extend no parameters
  ; from a word to a long)
  CLR.l d1

  ; Move no parameters to d1
  MOVE.w d7,d1

  ; Subtract no parameters from no-tags left
  SUB.l d1,d0

  ; d0 will be negative if not enough tags left, so compare with 0
  TST.l d0
  ; if less than zero then error
  BLT _AddTagsError      ;;;; Bugfix PR 17.7.96  was: BLE ;;;;
RTS

_AddTagsError:
  MOVE.l #_AddTagsMessage,d0
  TRAP #0

_AddTagsMessage:
Dc.b "There are too many tags to fit in this taglist!",0
Even


