* == rxexample.asm =====================================================
*
* Copyright (c) 1987 by William S. Hawes (All Rights Reserved)
*
* ======================================================================
* An example of an external function library for use with ARexx.  Defines
* the required Open, Close, Expuncge, and reserved entry points, and loads
* the arguments for calling the'C' language Dispatch() function.
*
* The initialization code opens the ARexx systems library and places the
* library base in the external _RexxSysBase, and places this library base
* in the external RexxExmpBase.
*
* N.B.  The convention for loading the 'C' language static data pointer into
* register A4 differs between compilers.  The present code loads A4 using
* the linker (BLINK) defined value _LinkerDB; this will have to be changed
* to use the Manx 'C' compiler.  Also note that calls to the library MUST
* preserve all regisrers except for A0/A1 and D0/D1; make sure that your
* compiler observes this!

         IDNT     RxExample
         SECTION  RxExample,CODE

         NOLIST
         INCLUDE  "rxexample.i"
         INCLUDE  "exec/resident.i"
         INCLUDE  "exec/initializers.i"
         LIST

         XREF     _LinkerDB            ; linker-defined static data pointer
         XREF     _RexxSysBase         ; user-defined library base
         XREF     _RexxExmpBase        ; user-defined library base
         XREF     _Dispatch            ; 'C' language dispatcher

         ; EXEC library entry points

         XLIB     CloseLibrary
         XLIB     FreeMem
         XLIB     OpenLibrary
         XLIB     Remove

* First executable location
Start:   moveq    #0,d0
         rts

LibPRI:  EQU   0                       ; priority field

* the "romtag" structure follows
romtag:
         dc.w   RTC_MATCHWORD          ; a magic word
         dc.l   romtag                 ; insurance
         dc.l   EndCode                ; end marker for checksum
         dc.b   RTF_AUTOINIT
         dc.b   RXEVERS                ; the Version number
         dc.b   NT_LIBRARY
         dc.b   LibPRI                 ; initialization priority
         dc.l   RXELib                 ; the library name
         dc.l   RXEId                  ; an ID string
         dc.l   Init                   ; initialization table

         CNOP     0,4
Init:    dc.l     re_SIZEOF
         dc.l     FuncTable
         dc.l     DataTable
         dc.l     InitEntry
   
* Entry point addresses go here, in the jump table order
FuncTable:   
         dc.l     Open                  ; required entry point
         dc.l     Close                 ; required
         dc.l     Expunge               ; required
         dc.l     Null                  ; reserved
         dc.l     Dispatch              ; 'Query' entry
         dc.l     -1                    ; table end marker
   
* Initializers for the allocated library structure
DataTable:
         INITBYTE LN_TYPE,NT_LIBRARY
         INITLONG LN_NAME,RXELib
         INITBYTE LIB_FLAGS,(LIBF_SUMUSED!LIBF_CHANGED)
         INITWORD LIB_VERSION,RXEVERS
         INITWORD LIB_REVISION,RXEREV
         INITLONG LIB_IDSTRING,RXEId
         dc.l     0

* This routine is called after the library has been loaded.  The library
* pointer is returned if no initialization errors occur.
* Registers:   A0 -- the segment list (from DOS)
*              A6 -- the Exec base
*              D0 -- the library pointer
InitEntry:   
         move.l   a5,-(sp)
         movea.l  d0,a5
         move.l   a6,re_SysBase(a5)    ; save the Exec base address
         move.l   a0,re_SegList(a5)    ; save our SegList pointer

         ; Open the required libraries.

         lea      RXSLib(pc),a1        ; library name
         moveq    #RXSVERS,d0          ; version
         CALLSYS  OpenLibrary
         move.l   d0,_RexxSysBase
         move.l   d0,re_REXXBase(a5)   ; opened?
         beq.s    1$                   ; no -- error
         move.l   a5,d0
         move.l   a5,_RexxExmpBase

1$:      movea.l  (sp)+,a5
         rts

* ============================     Open     =============================
* Increments the open count and returns the library pointer.
* Registers:   A6 -- library base
* Return:      D0 -- library base or 0
Open:    addq.w   #1,LIB_OPENCNT(a6)         ; increment open count
         bclr     #LIBB_DELEXP,LIB_FLAGS(a6) ; prevent delayed expunge
         move.l   a6,d0                      ; return the library base
         rts

* ============================     Close     =============================
* Decrements the open count, and checks whether the library is still open.
* If not, and if a 'delayed expunge' is pending, it is expunged.
* Registers:   A6 -- library base
* Return:      D0 -- seglist or 0
Close:
         moveq    #0,d0                      ; default return
         subq.w   #1,LIB_OPENCNT(a6)         ; still open?
         bne.s    1$                         ; yes ...
   
         ; Check whether to expunge the library.  A closed library is
         ; normally left in memory in case someone else opens it.

         btst     #LIBB_DELEXP,LIB_FLAGS(a6) ; a delayed expunge?
         beq.s    1$                         ; no ... hold off
         bsr.s    Expunge                    ; yes -- expunge it

1$:      rts

* ==========================     Expunge     ============================
* If the library is still open, the 'delayed expunge' flag is set, but the
* library is left in memory.
* Registers:   A6 -- library base
* Return:      D0 -- seglist or 0
Expunge:
         tst.w    LIB_OPENCNT(a6)            ; library still open?
         beq.s    1$                         ; no ...
         bset     #LIBB_DELEXP,LIB_FLAGS(a6) ; set 'delayed expunge'
         moveq    #0,d0                      ; no seglist
         bra.s    2$

1$:      move.l   re_SegList(a6),d0    ; the seglist
         movem.l  d0/a5/a6,-(sp)
         movea.l  a6,a5                ; Support base
         movea.l  re_SysBase(a5),a6    ; get Exec base pointer
         movea.l  a5,a1
         CALLSYS  Remove               ; unlink us

         ; Close the external libraries that were opened ...

         movea.l  re_REXXBase(a5),a1
         CALLSYS  CloseLibrary
   
         ; Calculate the size of the library node and release it.

         movea.l  a5,a1                ; node
         moveq    #0,d0
         move.w   LIB_NEGSIZE(a5),d0   ; forward extent
         suba.w   d0,a1                ; low memory extent
         add.w    LIB_POSSIZE(a5),d0   ; total length
         CALLSYS  FreeMem              ; give it back

         movem.l  (sp)+,d0/a5/a6       ; seglist=>D0

2$:      rts

Null:    moveq    #0,d0                ; reserved entry
         rts

         ; The 'dispatch' function ... pushes args and calls 'C' function.
         ; Must return an error code in D0 and a result string in A0.

Dispatch:
         move.l   a4,-(sp)
         subq.l   #4,sp

         ; Load the pointer to the global data area (generated by BLINK)

         lea      _LinkerDB,a4         ; global pointer

         ; Call the function

         move.l   sp,-(sp)             ; push return pointer
         move.l   a0,-(sp)             ; push argument
         jsr      _Dispatch            ; D0=error code
         addq.l   #8,sp                ; restore stack
         movea.l  (sp)+,a0             ; result string

         movea.l  (sp)+,a4
         rts

RXELib:  RXENAME                       ; the library name
RXEId:   RXEID                         ; an ID string
RXSLib:  RXSNAME                       ; ARexx Systems library
         CNOP     0,2
EndCode:                               ; a mysterious marker

         END
