* === hosttest.asm =====================================================
*
* Copyright (c) 1987 William S. Hawes (All Rights Reserved)
*
* ======================================================================
* This is an example "host" application for use with ARexx.  It opens a
* public message port called "MyHost" and waits for command messages to
* arrive.  The received command string is displayed and then checked for
* the special commands:
*   "BAD"   -- return an error code
*   "GOOD"  -- return success and a result string if requested
*   "CLOSE" -- close port and exit
*
* To exercise this example, enter "run hosttest" and then send commands
* from within ARexx using the ADDRESS 'MyHost' instruction.  The sample
* program "hosttest.rexx" provides an illustration.

         INCLUDE  "rexx/storage.i"
         INCLUDE  "rexx/rxslib.i"
         INCLUDE  "rexx/errors.i"

         INCLUDE  "libraries/dos.i"

         XREF     _AbsExecBase

         ; Exec library routines

         XLIB     AddPort
         XLIB     CloseLibrary
         XLIB     FindPort
         XLIB     Forbid
         XLIB     GetMsg
         XLIB     OpenLibrary
         XLIB     Permit
         XLIB     PutMsg
         XLIB     RemPort
         XLIB     ReplyMsg
         XLIB     WaitPort

         ; DOS library routines

         XLIB     Close
         XLIB     Delay
         XLIB     Open
         XLIB     Read
         XLIB     Write

DONE     SET      16
CLOSED   SET      31

STACKBF  EQU      MP_SIZE              ; message port structure
start    movea.l  _AbsExecBase,a6
         lea      -STACKBF(sp),sp      ; message port

         moveq    #0,d6                ; error code
         moveq    #0,d7                ; state flags

         ; Open the DOS library

         lea      DOSLib(pc),a1        ; DOS library
         moveq    #0,d0                ; any version
         CALLSYS  OpenLibrary
         move.l   d0,d5                ; "guaranteed"

         ; Open a window to display our wares ...

         lea      CONDef(pc),a1
         move.l   a1,d1
         move.l   #MODE_OLDFILE,d2
         exg      d5,a6
         CALLSYS  Open                 ; D0=filehandle
         exg      d5,a6
         move.l   d0,d4                ; opened?
         beq      CloseDOS             ; no

         ; Open the REXX system library

         lea      RXSLib(pc),a1        ; REXX library
         moveq    #0,d0                ; any version
         CALLSYS  OpenLibrary
         tst.l    d0                   ; library found?
         beq      NoLib                ; no
         movea.l  d0,a5                ; REXX library

         ; Check whether the port already exists ...

         CALLSYS  Forbid               ; no switching, please

         lea      PortName(pc),a1      ; our name
         CALLSYS  FindPort
         move.l   d0,d2                ; already exists?
         bne.s    1$                   ; yes

         ; Initialize the public message port

         movea.l  sp,a0                ; message port
         lea      PortName(pc),a1      ; our name
         exg      a5,a6
         CALLSYS  InitPort             ; D0=signal A1=port
         exg      a5,a6
         CALLSYS  AddPort              ; link it in

1$:      CALLSYS  Permit               ; restore switching
         tst.l    d2                   ; port found?
         bne.s    DupPort              ; yes

         ; Display the "ready" message

         lea      RdyMsg(pc),a0
         bsr      WriteMsg

         ; Wait for a message packet to arrive

WaitLoop
         movea.l  sp,a0                ; message port
         CALLSYS  WaitPort             ; wait for a message
         bra.s    CheckPort

         ; Withdraw the public port and check once again ...

RemovePort
         movea.l  sp,a1                ; message port
         CALLSYS  RemPort

CheckPort
         movea.l  sp,a0                ; message port
         CALLSYS  GetMsg               ; unlink it
         tst.l    d0                   ; a message?
         beq.s    1$                   ; no

         ; Process the message ...

         bsr      DoMessage
         bra.s    CheckPort            ; loop back

1$:      btst     #DONE,d7             ; close down?
         beq      WaitLoop             ; no

         bset     #CLOSED,d7           ; closed?
         beq.s    RemovePort           ; no

         ; Begin cleanup operations

         movea.l  sp,a0                ; message port
         exg      a5,a6
         CALLSYS  FreePort             ; release the signal bit
         exg      a5,a6 

         ; Close the REXX library

         movea.l  a5,a1
         CALLSYS  CloseLibrary
         bra.s    CloseFH

         ; Errors ...

NoLib    lea      ErrMsg1(pc),a0       ; couldn't open library
         bsr      WriteMsg
         bra.s    Delay

DupPort  lea      ErrMsg2(pc),a0       ; duplicate port
         bsr      WriteMsg

Delay    moveq    #100,d1
         exg      d5,a6
         CALLSYS  Delay
         exg      d5,a6
         moveq    #RC_ERROR,d6

         ; Close the display window

CloseFH  move.l   d4,d1                ; filehandle
         exg      d5,a6
         CALLSYS  Close
         exg      d5,a6

         ; Close the DOS library

CloseDOS movea.l  d5,a1
         CALLSYS  CloseLibrary

         move.l   d6,d0
         lea      STACKBF(sp),sp
         rts

* =========================     DoMessage      =========================
* Process the command messages.
* Registers:   D0 --message
DoMessage
         movem.l  d2/d3/a2/a3,-(sp)
         movea.l  d0,a2

         ; See if it came from REXX

         movea.l  a2,a0
         exg      a5,a6
         CALLSYS  IsRexxMsg            ; D0=boolean
         exg      a5,a6
         beq.s    NotREXX

         ; Display the command string

         movea.l  ARG0(a2),a0          ; command
         bsr      WriteMsg             ; display it

         ; Search backwards through the command table

         lea      (CTable+NUMTAB)(pc),a3
         moveq    #(NUMTAB>>1)-1,d3    ; loop count

         ; Compare the string in UPPERcase (for the command length)

         exg      a5,a6
1$:      movea.l  ARG0(a2),a0          ; command
         CALLSYS  LengthArgstring      ; D0=length A0=string
         lea      CTable(pc),a1        ; command table
         adda.w   -(a3),a1             ; test string
         CALLSYS  StrcmpU              ; D0={-1,0,1}
         dbeq     d3,1$                ; loop back
         exg      a5,a6
         bne.s    2$                   ; not recognized ...

         ; Perform the command

         lea      Jump(pc),a0          ; jump table
         add.w    d3,d3                ; scale index for 2 bytes
         adda.w   0(a0,d3.w),a0        ; function address
         jsr      (a0)                 ; D0=return code

         ; Acknowledge the message

         movem.l  d0/d1,-(sp)          ; push return/result
         lea      Recvd(pc),a0
         bsr      WriteMsg
         movem.l  (sp)+,d0/d1          ; pop return/result
         bra.s    Reply

         ; Command not recognized ...

2$:      lea      ErrMsg3(pc),a0       ; not recognized
         bsr      WriteMsg
         moveq    #5,d0                ; return code
         moveq    #0,d1
         bra.s    Reply

         ; non-REXX message received??

NotREXX  lea      ErrMsg4(pc),a0       ; not a REXX message
         bsr      WriteMsg
         moveq    #20,d0               ; return code
         moveq    #0,d1

         ; Return the message packet

Reply    movem.l  d0/d1,RESULT1(a2)
         movea.l  a2,a1                ; message packet
         CALLSYS  ReplyMsg

         movem.l  (sp)+,d2/d3/a2/a3
         rts

         ; The (trivial) action functions

BadFunc:
         moveq    #10,d0               ; error level
         moveq    #0,d1                ; no secondary
         rts

         ; Set the 'close' flag

CloseFunc:
         bset     #DONE,d7             ; close flag
         moveq    #0,d0                ; all ok
         moveq    #0,d1
         rts

         ; Returns a result string if one is requested.

GoodFunc:
         moveq    #0,d0                ; default return
         move.l   ACTION(a2),d1        ; action code
         btst     #RXFB_RESULT,d1      ; result requested?
         beq.s    1$                   ; no

         ; Create the return string ("All OK")

         lea      OKMsg(pc),a0
         exg      a5,a6
         CALLSYS  Strlen               ; D0=length A0=string
         CALLSYS  CreateArgstring      ; D0=A0=argstring
         exg      a5,a6

1$:      move.l   d0,d1                ; secondary return
         moveq    #0,d0                ; all ok
         rts

* ===========================     WriteMsg     =========================
* Displays a message on our "Host" window
WriteMsg
         movem.l  d2/d3/a6,-(sp)
         movea.l  d5,a6

         move.l   d4,d1                ; filehandle
         move.l   a0,d2                ; string
1$:      tst.b    (a0)+                ; null?
         bne.s    1$                   ; loop back
         subq.l   #1,a0
         move.l   a0,d3
         sub.l    d2,d3                ; length
         CALLSYS  Write

         movem.l  (sp)+,d2/d3/a6
         rts

         ; Offsets to command functions

Jump     dc.w     BadFunc-Jump
         dc.w     CloseFunc-Jump
         dc.w     GoodFunc-Jump

         ; Offsets to the commands

CTable   dc.w     command1-CTable
         dc.w     command2-CTable
         dc.w     command3-CTable
NUMTAB   EQU      *-CTable             ; entries*2

         ; The commands we recognize

command1 dc.b     'BAD'                ; error return
command2 dc.b     'CLOSE'              ; shut down
command3 dc.b     'GOOD'               ; All OK

         ; String data

DOSLib   dc.b     'dos.library',0
RXSLib   RXSNAME
CONDef   dc.b     'CON:0/0/640/60/MyHost/a',0
PortName dc.b     'MyHost',0

OKMsg    dc.b     'All OK',0
RdyMsg   dc.b     'Host application "MyHost" ready for business',10,0
ErrMsg1  dc.b     'Unable to open rexxsyslib.library',10,0
ErrMsg2  dc.b     'Port "MyHost" already exists',10,0
ErrMsg3  dc.b     ' not recognized',10,0
ErrMsg4  dc.b     'Not a REXX message',10,0
Recvd    dc.b     ' command received',10,0
         CNOP     0,2

         END
