* ========================     loadlib.asm      =========================
* Usage: LOADLIB [dev:dir/]library-name  (** CLI only **)
*
* Loads the specified library and links it into the system list, after
* checking to see if it's already open.  Searches the current directory
* (or specified device).
* Written March, 1987 by William S. Hawes
* ============> Distribute freely to all Amigoid life-forms <============

         SECTION  RexxSys,CODE

         NOLIST
         INCLUDE  "exec/types.i"
         INCLUDE  "exec/nodes.i"
         INCLUDE  "exec/lists.i"
         INCLUDE  "exec/libraries.i"
         INCLUDE  "exec/resident.i"
         INCLUDE  "exec/interrupts.i"
         INCLUDE  "exec/execbase.i"
         INCLUDE  "exec/initializers.i"
         LIST

* Macro to call a library function (assumes library pointer is in A6)
CALLSYS  MACRO    * FunctionName
         CALLLIB  _LVO\1
         ENDM

* Macro to define an external library entry point (offset)
XLIB     MACRO    * FunctionName
         XREF     _LVO\1
         ENDM

         XREF     _AbsExecBase

         ; EXEC library functions

         XLIB     AddLibrary
         XLIB     CloseLibrary
         XLIB     FindName
         XLIB     MakeLibrary
         XLIB     OpenLibrary

         ; DOS library functions

         XLIB     LoadSeg
         XLIB     Output
         XLIB     UnLoadSeg
         XLIB     Write

STACKBUF EQU      80
start:   movea.l  _AbsExecBase,a6
         lea      -STACKBUF(sp),sp
         moveq    #0,d6                ; return code

         ; Copy the name string to the stack buffer 

         movea.l  sp,a2
         moveq    #STACKBUF-1,d2       ; loop count

1$:      move.b   (a0)+,d0             ; get a character
         move.b   d0,(a2)+             ; copy it
         cmpi.b   #':',d0              ; device specifier?
         beq.s    2$                   ; yes
         cmpi.b   #'/',d0              ; subdirectory?
         bne.s    3$                   ; no
2$:      moveq    #-1,d7               ; ... set flag
3$:      cmpi.b   #' ',d0              ; end of name?
         dble     d2,1$                ; no ...
         bhi      NotFound             ; name too long ...
         clr.b    -(a2)                ; install a NULL

         ; Open the DOS library

OpenDOS:
         lea      DOSlib(pc),a1
         moveq    #0,d0
         CALLSYS  OpenLibrary
         move.l   d0,d5

         suba.l   sp,a2                ; final length
         move.l   a2,d0                ; library name given?
         beq      ShowFormat           ; no ...
         subq.w   #1,d0                ; one character?
         bne.s    CheckLib             ; no
         cmpi.b   #'?',(sp)            ; a '?' character?
         beq      ShowFormat           ; yes

         ; Attempt to open the library directly, unless the name
         ; includes a device or directory specification ...

CheckLib:
         tst.w    d7                   ; device specifier?
         bne.s    1$                   ; yes
         movea.l  sp,a1                ; library name
         moveq    #0,d0
         bsr      TestLibrary          ; available?
         bne      CloseDOS             ; yes

         ; Attempt to find the library in the current directory

1$:      move.l   sp,d1                ; supplied name
         exg      d5,a6
         CALLSYS  LoadSeg              ; return: D0=seglist
         exg      d5,a6
         move.l   d0,d3                ; file loaded?
         beq.s    NotFound             ; no ...

         ; Search the loaded code for the ROMTAG word ...

         lsl.l    #2,d0                ; convert to APTR
         movea.l  d0,a3
         move.l   #RTC_MATCHWORD,d0    ; the magic word
         moveq    #-1,d1               ; search count

2$:      cmp.w    (a3)+,d0             ; the romtag?
         dbeq     d1,2$                ; loop back
         bne.s    NotALib              ; not found

         subq.l   #2,a3                ; start of structure
         cmpa.l   2(a3),a3             ; confirmed?
         bne.s    NotALib              ; no

         ; Check whether the library already exists ...

         lea      LibList(a6),a0       ; library list header
         movea.l  RT_NAME(a3),a1       ; library name
         CALLSYS  FindName
         tst.l    d0                   ; found?
         bne.s    CloseDOS             ; yes

         ; Load the initialization data and make the library ...

         movea.l  RT_INIT(a3),a1       ; initialization table
         movem.l  (a1),d0/a0/a1/a2     ; load from initialization table
         move.l   d3,d1                ; library seglist
         CALLSYS  MakeLibrary
         tst.l    d0                   ; success?
         beq.s    NotALib              ; no

         ; Link the library into the system list

         movea.l  d0,a1
         CALLSYS  AddLibrary
         bra.s    CloseDOS

         ; Error:  segment loaded, but it wasn't a library ...

NotALib:
         lea      ErrMsg2(pc),a0
         moveq    #ERRLEN2,d0
         bsr      WriteMsg
         move.l   d3,d1                ; seglist
         exg      d5,a6
         CALLSYS  UnLoadSeg            ; release it
         exg      d5,a6
         moveq    #10,d6
         bra.s    CloseDOS

         ; Error:  library file not found ...

NotFound:
         lea      ErrMsg1(pc),a0
         moveq    #ERRLEN1,d0
         bsr      WriteMsg
         moveq    #10,d6
         bra.s    CloseDOS

         ; Display the command format 

ShowFormat:
         lea      ErrMsg3(pc),a0
         moveq    #ERRLEN3,d0
         bsr      WriteMsg
         moveq    #5,d6

         ; Close the DOS library

CloseDOS:
         movea.l  d5,a1
         CALLSYS  CloseLibrary

Exit:    move.l   d6,d0                ; return code
         lea      STACKBUF(sp),sp
         rts

* ========================     TestLibrary     =========================
* Tests whether the named library is available ...
* Registers:   A1 -- library name
*              D0 -- version
*              A6 -- EXEC base
* Return:      D0 -- library base (test only!)
TestLibrary:
         CALLSYS  OpenLibrary          ; return: D0=library base
         move.l   d0,-(sp)             ; library found?
         beq.s    1$                   ; no
         movea.l  d0,a1                ; yes
         CALLSYS  CloseLibrary         ; ... close it

1$:      move.l   (sp)+,d0             ; set CCR
         rts

* =========================      WriteMsg     =========================
* Writes a message to the console ...
* Registers:   A0 -- message
*              D0 -- length
*              D5 -- DOS library base
WriteMsg:
         movem.l  d2/d3,-(sp)
         move.l   a0,d2                ; message
         move.l   d0,d3                ; length
         exg      d5,a6
         CALLSYS  Output               ; output stream
         move.l   d0,d1
         CALLSYS  Write                ; write it ...
         exg      d5,a6
         movem.l  (sp)+,d2/d3
         rts

DOSlib   dc.b     'dos.library',0
ErrMsg1  dc.b     'Library not found',10,0
ERRLEN1  EQU      18
ErrMsg2  dc.b     'Not a library file',10,0
ERRLEN2  EQU      19
ErrMsg3  dc.b     'Format:  LOADLIB [dev:dir/]library',10,0
ERRLEN3  EQU      35
         CNOP     0,2
