*************************************************************************
* ImageFX Module Startup Code
*
* Based on the Commodore-supplied example library, if you didn't
* notice.
*
*************************************************************************


SAS_FLOAT	EQU	1	Enable SAS floating point init
SAS_STACK	EQU	1	Enable SAS stack depth checking init


   		NOLIST

   		INCLUDE "exec/types.i"
   		INCLUDE "exec/libraries.i"
   		INCLUDE "exec/lists.i"
   		INCLUDE "exec/alerts.i"
   		INCLUDE "exec/initializers.i"
   		INCLUDE "exec/resident.i"
   		INCLUDE "exec/tasks.i"
   		INCLUDE "libraries/dos.i"
   		INCLUDE "libraries/dosextens.i"

   		INCLUDE "scan/mod.i"


BHS	 	MACRO
	 	bcc.\0  \1 ;\0 is the extension used on the macro (such as ".s")
	 	ENDM

BLO	 	MACRO
	 	bcs.\0  \1
	 	ENDM


   		XREF   	_AbsExecBase

   		XREF	_LVOOpenLibrary
   		XREF	_LVOCloseLibrary
   		XREF	_LVOAlert
   		XREF	_LVOFreeMem
   		XREF	_LVORemove

   		XREF	_LVOFindTask

   		; These must be defined in the C code somewhere...
   		XREF   	_FuncTable        	; Function table array
   		XREF   	_LibraryType          	; Type of module (NT_#?)
   		XREF   	_LibraryID            	; Library ID string
   		XREF   	_UserOpen             	; Module-specific Open code
   		XREF   	_UserClose            	; Module-specific Close code

		IFNE	SAS_FLOAT
                ; Used to allow floating point in modules.
   		XREF	___fpinit
   		XREF	___fpterm
   		ENDC	SAS_FLOAT


***********************************************************************
*
* Library data structures
*
***********************************************************************

   		LIST

;----------------------------------------------------------------------
; The first executable location.  This should return an error
; in case someone tried to run you as a program (instead of
; loading you as a library).

Start:
   		moveq	#-1,d0
   		rts

;-----------------------------------------------------------------------
; A romtag structure.  Both "exec" and "ramlib" look for
; this structure to discover magic constants about you
; (such as where to start running you from...).
;

initDDescrip:
     		DC.W	RTC_MATCHWORD   ; RT_MATCHWORD
     		DC.L	initDDescrip    ; RT_MATCHTAG
     		DC.L	EndCode         ; RT_ENDSKIP
     		DC.B	RTF_AUTOINIT    ; RT_FLAGS
     		DC.B	MOD_VERSION     ; RT_VERSION
     		DC.B	NT_LIBRARY      ; RT_TYPE
     		DC.B	0		; RT_PRI
     		DC.L	0       	; RT_NAME
     		DC.L	_LibraryID      ; RT_IDSTRING
     		DC.L	Init            ; RT_INIT


		; force word allignment
   		DS.W	0


;----------------------------------------------------------------------
; The romtag specified that we were "RTF_AUTOINIT".  This means
; that the RT_INIT structure member points to one of these
; tables below.  If the AUTOINIT bit was not set then RT_INIT
; would point to a routine to run.

Init:
   		DC.L	xmodbase_SIZEOF   ; size of library base data space
   		DC.L	_FuncTable        ; pointer to function initializers (external)
   		DC.L	dataTable         ; pointer to data initializers
   		DC.L	initRoutine       ; routine to run


;----------------------------------------------------------------------
; The data table initializes static data structures.
; The format is specified in exec/InitStruct routine's
; manual pages.  The INITBYTE/INITWORD/INITLONG routines
; are in the file "exec/initializers.i".  The first argument
; is the offset from the library base for this byte/word/long.
; The second argument is the value to put in that cell.
; The table is null terminated

dataTable:
   		INITBYTE   	LIB_FLAGS,LIBF_SUMUSED!LIBF_CHANGED
   		INITWORD   	LIB_VERSION,MOD_VERSION
   		INITWORD   	LIB_REVISION,MOD_REVISION
   		INITLONG   	LIB_IDSTRING,_LibraryID
   		DC.L		0


;----------------------------------------------------------------------
; This routine gets called after the library has been allocated.
; The library pointer is in D0.  The segment list is in A0.
; If it returns non-zero then the library will be linked into
; the library list.

initRoutine:
		;------ get the library pointer into a convenient A register
		move.l	a5,-(sp)
		move.l	d0,a5

		;------ save a pointer to exec
		move.l	a6,mb_SysLib(a5)
		move.l	a6,_SysBase

		;------ save a pointer to our loaded code
		move.l	a0,mb_Segment(a5)

		IFNE	SAS_STACK

		;------ initialize SAS stack depth checking
		suba.l	a1,a1
		jsr	_LVOFindTask(a6)
		move.l	d0,a1
		move.l	pr_CLI(a1),d1
		beq.s	11$
		lsl.l	#2,d1
		move.l	d1,a0
		move.l	cli_DefaultStack(a0),d1
		lsl.l	#2,d1
		bra.s	21$
11$
		move.l	a7,d1
		sub.l	TC_SPLOWER(a1),d1
21$
		move.l	a7,d0
		sub.l	d1,d0
		add.l	#128,d0
		move.l	d0,___base

		ENDC	SAS_STACK

		;------ open the dos library
		lea	dosName(pc),a1
		moveq	#0,d0
		jsr	_LVOOpenLibrary(a6)

		move.l	d0,_DOSBase
		bne.s	1$

		;------ can't open the dos!  what gives
		ALERT	AG_OpenLib!AO_DOSLib

1$:
		;------ initialize floating point libraries
		IFNE	SAS_FLOAT
		jsr      ___fpinit(PC)
                ENDC	SAS_FLOAT

		move.l	a5,d0			; restore libbase
OUT:
		move.l	(sp)+,a5
		rts

		IFNE	SAS_FLOAT

;--------------------------------------------------------------------------
; We need this because of SAS lcmieee.lib floating point initialization.
; If it fails, it calls XCEXIT(), which we are trapping here and turning
; into just a standard failure return.  Not nice, but it seems to work.
;
		xdef	__XCEXIT
__XCEXIT:
		moveq	#0,d0
		addq.l	#8,sp
		bra.s	OUT

                ENDC	SAS_FLOAT


************************************************************************
*
* Here begins the system interface commands.  When the user calls
* OpenLibrary/CloseLibrary/RemoveLibrary, this eventually gets translated
* into a call to the following routines (Open/Close/Expunge).  Exec
* has already put our library pointer in A6 for us.  Exec has turned
* off task switching while in these routines (via Forbid/Permit), so
* we should not take too long in them.
*
************************************************************************

   		XDEF   	_LibOpen
   		XDEF   	_LibClose
   		XDEF   	_LibExpunge
   		XDEF   	_LibNull

;--------------------------------------------------------------------
; Open returns the library pointer in d0 if the open
; was successful.  If the open failed then null is returned.
; It might fail if we allocated memory on each open, or
; if only open application could have the library open
; at a time...

_LibOpen:	; ( libptr:a6, version:d0 )

		move.l	a4,-(sp)	; Save opener's A4...

                ; Set type of module.
   		move.b  _LibraryType,LN_TYPE(a6)

		; Set module's global pointers...
		move.l	a6,_ModuleBase
		move.l	mb_ScanBase(a6),a0
		move.l	a0,_ScanBase
		move.l	sb_IntuitionBase(a0),_IntuitionBase
		move.l	sb_GfxBase(a0),_GfxBase

   		; Call module's 'C' open code
   		move.l a6,-(sp)
   		bsr    _UserOpen
   		move.l (sp)+,a6
   		tst.l  d0
   		bne.s  1$

   		; User open failed, abort open
   		move.l (sp)+,a4		; Restore A4!
   		moveq  #0,d0		; Fail code
   		rts

1$:
   		; mark us as having another opener
   		addq.w   #1,LIB_OPENCNT(a6)

   		; prevent delayed expunges
;   		bclr   #LIBB_DELEXP,LIB_FLAGS(a6)

   		move.l   (sp)+,a4	; Restore opener's A4

   		move.l   a6,d0		; Success
   		rts


;----------------------------------------------------------------
; There are two different things that might be returned from
; the Close routine.  If the library is no longer open and
; there is a delayed expunge then Close should return the
; segment list (as given to Init).  Otherwise close should
; return NULL.

_LibClose:	; ( libptr:a6 )

   		move.l  a4,-(sp)		; Save opener's A4...

   		;------ Call 'C' close code
   		move.l  a6,-(sp)
   		bsr     _UserClose
   		move.l  (sp)+,a6

   		;------ set the return value
   		moveq   #0,d0

   		;------ mark us as having one fewer openers
   		subq.w   #1,LIB_OPENCNT(a6)

   		;------ see if there is anyone left with us open
   		bne.s   1$

   		;------ We expunge the library no matter what on the last Close
;   		;------ see if we have a delayed expunge pending
;  		btst   #LIBB_DELEXP,LIB_FLAGS(a6)
;  		beq.s   1$

   		;------ do the expunge
   		bsr   _LibExpunge
1$:
   		move.l (sp)+,a4			; Restore opener's A4...
   		rts


;---------------------------------------------------------------
; There are two different things that might be returned from
; the Expunge routine.  If the library is no longer open
; then Expunge should return the segment list (as given to
; Init).  Otherwise Expunge should set the delayed expunge
; flag and return NULL.
;
; One other important note: because Expunge is called from
; the memory allocator, it may NEVER Wait() or otherwise
; take long time to complete.

_LibExpunge:	; ( libptr: a6 )

		movem.l	d2/a5/a6,-(sp)
		move.l	a6,a5
		move.l	mb_SysLib(a5),a6

		;------ see if anyone has us open
		tst.w	LIB_OPENCNT(a5)
		beq.s	1$

		;------ it is still open.  set the delayed expunge flag
		bset	#LIBB_DELEXP,LIB_FLAGS(a5)
		moveq	#0,d0
		bra.s	Expunge_End

1$:
		IFNE	SAS_FLOAT
		jsr	___fpterm(PC)
		ENDC	SAS_FLOAT

		;------ go ahead and get rid of us.  Store our seglist in d2
		move.l	mb_Segment(a5),d2

		; no need to remove library - we were never added
		; to public library list!

		;------ close the dos library
		move.l	_DOSBase,a1
		jsr	_LVOCloseLibrary(a6)

		;------ free our memory
		moveq	#0,d0
		move.l	a5,a1
		move.w	LIB_NEGSIZE(a5),d0

		sub.l	d0,a1
		add.w	LIB_POSSIZE(a5),d0

		jsr	_LVOFreeMem(a6)

		;------ set up our return value, the segment
		move.l	d2,d0

Expunge_End:
		movem.l	(sp)+,d2/a5/a6
		rts


;----------------------------------------------------------
; Reserved library vector should just return 0.
;

_LibNull:
		moveq	#0,d0
		rts

;----------------------------------------------------------
; If language text has been located and loaded, use the
; string associated with the given index.  Otherwise use
; the default string passed in.
;
; May be used by a module to provide the ability to alter
; the module's text strings, for localization purposes.
;
; char *GetStr(LONG index, char *default);
;

		XDEF	_GetStr
_GetStr:
		move.l	_ModuleBase,a0
		tst.l	mb_Text(a0)
		beq.s	1$
		move.l	mb_Text(a0),a0
		move.l	4(sp),d0
		add.l	d0,d0
		add.l	d0,d0
		move.l	0(a0,d0.l),d0
		bra.s	2$
1$		move.l	8(sp),d0
2$		rts


**********************************************************************
*
* Data section
*
**********************************************************************

   		XDEF   	_SysBase
   		XDEF   	_DOSBase
                XDEF    _IntuitionBase
                XDEF    _GfxBase
                XDEF    _ModuleBase
                XDEF    _ScanBase


dosName:	DC.B    'dos.library',0
   		CNOP	0,2


		SECTION __MERGED,DATA

_SysBase:	DC.L    0
_DOSBase:	DC.L	0

_IntuitionBase  DC.L    0
_GfxBase        DC.L    0
_ModuleBase     DC.L    0
_ScanBase       DC.L    0


; For SAS stack depth checking...
		IFNE	SAS_STACK
		XDEF	___base
___base:	DC.L	0
		ENDC	SAS_STACK

; These are used for SAS floating point...
		IFNE	SAS_FLOAT
		XDEF	__FPERR,__SIGFPE
__FPERR		DC.L	0
__SIGFPE	DC.L	0
		ENDC	SAS_FLOAT

;--------------------------------------------------------------------
; This stuff was added for modules to compile under SAS6.2...

		XDEF	__OSERR
__OSERR:	DC.L	0		; OS error codes (SAS6.2)
		XDEF	__ProgramName
__ProgramName	DC.L	0		; Program Name??? (SAS6.2)



; EndCode is a marker that show the end of your code.
; Make sure it does not span sections nor is before the
; rom tag in memory!  It is ok to put it right after
; the rom tag -- that way you are always safe.  I put
; it here because it happens to be the "right" thing
; to do, and I know that it is safe in this case.

EndCode:
		END

