* === waitforport.asm ==================================================
*
* Written by William S. Hawes (1988)  >>> freely distributable <<<
*
* ======================================================================
* Checks for a public message port and waits (for up to 10 seconds) for
* the port to appear.  The port name is case-sensitive.
* USAGE: waitforport [-immediate] port-name

         INCLUDE  "exec/types.i"
         INCLUDE  "exec/macros.i"
         INCLUDE  "exec/tasks.i"
         INCLUDE  "exec/interrupts.i"
         INCLUDE  "exec/execbase.i"

         INCLUDE  "libraries/dos.i"

         XREF     _AbsExecBase

         XLIB     CloseLibrary
         XLIB     FindPort
         XLIB     OpenLibrary

         XLIB     Delay
         XLIB     Output
         XLIB     Write

IMMED    EQU      0

WAITINT  EQU      5                    ; interval in ticks
NUMINT   EQU      100                  ; number of intervals
start    movea.l  _AbsExecBase,a6
         movea.l  a0,a2                ; argument string

         move.l   d0,d2                ; length
         moveq    #RETURN_OK,d6        ; return code

         adda.l   d2,a0                ; end of string
         subq.w   #1,d2                ; loop count

1$:      clr.b    (a0)                 ; null byte
         cmpi.b   #' ',-(a0)           ; > blank?
         dbhi     d2,1$                ; loop back
         addq.w   #1,d2                ; restore length

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

         cmpi.w   #1,d2                ; one character?
         bne.s    2$                   ; no
         cmpi.b   #'?',(a2)            ; display format?
         beq      ShowFmt              ; yes

2$:      moveq    #STATEI,d3           ; 'Idle' state
         moveq    #' ',d4              ; load blank
         bra.s    KEnd                 ; jump in

KCodes   dc.b     'I'                  ; keyword codes
KCODES   EQU      *-KCodes             ; length
         CNOP     0,2

KBegin   move.b   (a2),d1              ; test character
         jmp      KBegin(pc,d3.w)

         ; 'Scan' state ... check for the start of an option keyword.

KScan    bclr     #5,d1                ; UPPERcase
         moveq    #KCODES-1,d0
1$:      cmp.b    KCodes(pc,d0),d1     ; match?
         dbeq     d0,1$                ; loop back
         bne.s    Error1               ; ... invalid option
         bset     d0,d7                ; set flag
         moveq    #STATEW,d3           ; enter 'word' state

         ; 'Word' state ... skip the remainder of the keyword.

KWord    cmp.b    d4,d1                ; > blank?
         bhi.s    KNext                ; yes
         moveq    #STATEI,d3           ; ... 'idle' state

         ; Skip "white space" until option switch ...

KIdle    cmp.b    d4,d1                ; white space?
         bls.s    KNext                ; yes

         ; Check for the start of an option keyword

         moveq    #STATES,d3           ; 'scan' state
         movea.l  a2,a1                ; save position
         cmpi.b   #'-',d1              ; option switch?
         bne.s    KDone                ; no ... all done

KNext    addq.l   #1,a2                ; advance pointer
KEnd     dbf      d2,KBegin            ; loop back

STATEI   EQU      KIdle-KBegin
STATES   EQU      KScan-KBegin
STATEW   EQU      KWord-KBegin

KDone    addq.w   #1,d2                ; restore length
         beq.s    Error2               ; ... no port name

         moveq    #0,d4                ; clear count
         btst     #IMMED,d7            ; 'immediate'?
         bne.s    Check                ; yes
         moveq    #NUMINT-1,d4         ; intervals
         bra.s    Check                ; jump in

         ; Wait for a while ...

Wait     moveq    #WAITINT,d1          ; interval
         exg      d5,a6
         CALLSYS  Delay
         exg      d5,a6

         ; Check for specified port

Check    movea.l  a2,a1                ; port name
         CALLSYS  FindPort             ; D0=port node
         tst.l    d0                   ; port found?
         dbne     d4,Wait              ; loop back
         beq.s    Warning              ; not found
         bra.s    CloseDOS

ShowFmt  lea      Usage(pc),a0
         bsr.s    WriteMsg
         bra.s    CloseDOS

         ; Error ... no port name given

Error1   lea      ErrMsg1(pc),a0         ; usage format
         bsr.s    WriteMsg
         bra.s    Warning

Error2   lea      ErrMsg2(pc),a0       ; "invalid option"
         bsr.s    WriteMsg

Warning  moveq    #RETURN_WARN,d6

CloseDOS movea.l  d5,a1
         CALLSYS  CloseLibrary

         move.l   d6,d0                ; return code
         rts

* ==========================      WriteMsg     =========================
* Writes a message to the standard output stream.
* Registers:   A0 -- message
*              D0 -- length
*              D5 -- DOS library base
WriteMsg
         movem.l  d2/d3/a6,-(sp)
         movea.l  d5,a6

         move.l   a0,d2                ; message
         moveq    #-1,d3
1$:      addq.l   #1,d3                ; increment length
         tst.b    (a0)+                ; null?
         bne.s    1$                   ; no

         CALLSYS  Output               ; output stream
         move.l   d0,d1
         CALLSYS  Write                ; write it ...
         movem.l  (sp)+,d2/d3/a6
         rts

         ; String constants

DOSLib   dc.b     'dos.library',0
Usage    dc.b     'USAGE: waitforport [-immediate] port-name',10,0

ErrMsg1  dc.b     'Invalid option',10,0
ErrMsg2  dc.b     'No port name specified',10,0
         CNOP     0,2

         END
