;JAH BY DANIEL WOLF PH.D. 02/25/90
;COPYRIGHT 1990 BY ANTIC PUBLICATIONS
;JAH SENDS A MESSAGE TO A NAMED PORT AND PRINTS OUT THE REPLY!
;EXAMPLE    JAH PORTNAME MESSAGE

;Aztec users: as -CD jah.asm  ln jah.o
;and change DATA to DSEG down below!


SIZE.MP                EQU $22

LVO.ALLOCMEM           EQU $FFFFFF3A
LVO.FREEMEM            EQU $FFFFFF2E

LVO.ADDPORT            EQU $FFFFFE9E
LVO.REMPORT            EQU $FFFFFE98
LVO.FINDPORT           EQU $FFFFFE7A
LVO.WAITPORT           EQU $FFFFFE80
LVO.REMOVE             EQU $FFFFFF04

LVO.FINDTASK           EQU $FFFFFEDA

LVO.PUTMSG             EQU $FFFFFE92
LVO.GETMSG             EQU $FFFFFE8C
LVO.REPLYMSG           EQU $FFFFFE86

LVO.FREESIGNAL         EQU $FFFFFEB0
LVO.ALLOCSIGNAL        EQU $FFFFFEB6

LVO.OPENLIBRARY        EQU $FFFFFDD8
LVO.CLOSELIBRARY       EQU $FFFFFE62

LVO.WRITE      EQU $FFFFFFD0       ;THESE TWO ARE DOS LIBRARY OFFSETS
LVO.OUTPUT     EQU $FFFFFFC4

LIST.HEAD      EQU $0          ;SAME AS lh_Head
LIST.TAIL      EQU $4          ;lh_Tail
MEMF_PUBLIC    EQU $0
MEMF_CLEAR     EQU $10000
MP.MSGLIST     EQU $14         ;mp_MsgList
MP.SIGTASK     EQU $10         ;mp_SigTask
MP.SIGBIT      EQU $F          ;mp_SigBit
MP.FLAGS       EQU $E          ;mp_Flags
MSG.REPLYPORT  EQU $E          ;mn_ReplyPort
NODE.PRED      EQU $4          ;ln_Pred
NODE.NAME      EQU $A          ;ln_Name
NODE.TYPE      EQU $8          ;ln_Name
NODE.PRI       EQU $9          ;ln_Pri
NT_MSGPORT     EQU $4
NT_MESSAGE     EQU $5
PA_SIGNAL      EQU $0


;**************** EXEC NEWLIST MACRO

NEWLIST MACRO     ;An
 MOVE.L \1,(\1)                         ;MOVE An TO (An)
 MOVE.L \1,LIST.HEAD(\1)                ;SHUFFLE HEAD AND TAIL POINTERS
 ADD.L #LIST.TAIL,LIST.HEAD(\1)
 CLR.L LIST.TAIL(\1)
 MOVE.L \1,LIST.TAIL+NODE.PRED(\1)      ;SO THIS PORT IS FIRST IN LIST
 ENDM

;*************** AND A FEW SIMPLE PROGRAMMING MACROS

SYSCALL MACRO                   ;CALL EXEC ROUTINES RELATIVE TO A6
 JSR LVO.\1(A6)
 ENDM

PUSH MACRO                      ;PUSH A REGISTER ONTO STACK
 MOVEM.L \1,-(SP)
 ENDM

PULL MACRO                      ;PULL A REGISTER FROM STACK
 MOVEM.L (SP)+,\1
 ENDM

ZERO MACRO                      ;ZERO OUT A DATA REG
 MOVEQ #0,\1
 ENDM

ZERA MACRO                      ;ZERO OUT AN ADDRESS REG
 SUBA.L \1,\1
 ENDM

PUBLICMEM MACRO ;SIZE           ;ALLOCATE SOME PUBLIC MEMORY
 MOVE.L #MEMF_PUBLIC!MEMF_CLEAR,D1
 MOVE.L \1,D0
 SYSCALL ALLOCMEM
 ENDM

;************** HERES JAH **********

MAIN                    ;HERES THE CODE FOR JAH
 MOVE.L 4,A6            ;GET EXEC LIBRARY PTR INTO A6
 ZERA A4                ;THIS WILL GET THE ADDRESS OF OUR MSGPORT
 ZERA A5                ;CLEAR A5 UNTIL DOS LIBRARY IS OPENED
 CLR.B -1(A0,D0.W)      ;REPLACE LINEFEED WITH NULL
 TST.B (A0)             ;IS ANYTHING IN STRING?
 BEQ EXIT               ;IF COMMAND LINE HAS ZERO LENGTH JUST QUIT
 CMPI.B #63,D0          ;DONT ACCEPT COMMAND LINE LONGER THAN 63 CHARACTERS
 BGT EXIT

 CLR.B -1(A0,D0.W)      ;FORCE A NULL BYTE AT END OF COMMAND LINE

PARSECOMMANDLINE
 LEA PORTNAME,A1        ;POINTER TO STORAGE FOR DESTINATION PORT NAME
 LEA THEMESSAGE,A2      ;POINTER TO DATA SECTION OF JAHMESSAGE STRUCTURE

GETPNCHAR
 MOVE.B (A0)+,D1        ;GET A BYTE OF COMMAND LINE
 BEQ EXIT               ;IF NULL THEN NO MESSAGE! => EXIT
 CMPI.B #$20,D1         ;IS IT A SPACE?
 BEQ GETMSGCHAR         ;YES - WE PASSED THE DESTINATION PORT NAME
 MOVE.B D1,(A1)+        ;MOVE PORTNAME TO STORAGE FOR CONVENIENCE
 BNE GETPNCHAR

GETMSGCHAR
 MOVE.B (A0)+,D1        ;GET BYTES PAST FIRST SPACE
 BEQ MAKEOURPORT        ;AND KEEP GETTING EM UNTIL WE HIT THE NULL
 MOVE.B D1,(A2)+        ;WE FORCED AT THE END OF THE COMMAND LINE
 BRA GETMSGCHAR         ;TRANSFER THEM TO THE DATA SECTION OF JAHMESSAGE

MAKEOURPORT
 ZERA A0                ;CLEAR A0, NO NAME NEEDED FOR PORT (NO CALL TO ADDPORT)
 ZERO D0                ;SET A PRIORITY OF ZERO FOR REPLY PORT
 BSR MAKEAPORT          ;PUTS ADDRESS OF PORT IN A4 AND D0 (OR 0 IN D0 IF FAIL)
 BEQ EXIT               ;QUIT IF IT FAILS

 LEA JAHMESSAGE,A0
 MOVE.L D0,MSG.REPLYPORT(A0)    ;TELL OUR MESSAGE TO REPLY BACK TO THIS PORT

ISOTHERPORTTHERE
 LEA PORTNAME,A1        ;SETUP POINTER TO NAME OF DESTINATION PORT
 ZERO D0
 SYSCALL FINDPORT       ;NOW LOOK FOR PORT BY NAME!
 TST.L D0
 BEQ EXIT               ;BYE-BYE IF PORT NOT FOUND
 MOVE.L D0,A0           ;PUT ADDRESS OF PORT IN A0 (WE NEED IT THERE)

SENDITTOPORT
 LEA JAHMESSAGE,A1       ;PTR TO PORT ALREADY IN A0
 SYSCALL PUTMSG         ;NOW SEND JAHMESSAGE TO NAMED DESTINATION PORT

WAITFORREPLY
 MOVE.L A4,A0           ;ADDRESS OF OUR (REPLY) PORT
 SYSCALL WAITPORT       ;NOW WAIT FOR PROGRAM TO RECEIVE THE REPLY


 MOVE.L A4,A0           ;GOT A SIGNAL NOW GET THE MESSAGE REPLY
 SYSCALL GETMSG
 TST.L D0               ;NO MESSAGE?
 BEQ EXIT               ;IF THERE IS NO MESSAGE SOMETHINGS WRONG

;*** THIS PART OPTIONAL - PRINTS OUT THE REPLY TO THE MESSAGE
;*** VERY HANDY FOR DEBUGGING YOUR COMMUNICATION METHODS

 LEA _DOSNAME,A1        ;FIRST OPEN DOS LIBRARY
 ZERO D0
 SYSCALL OPENLIBRARY
 TST.L D0
 BEQ EXIT               ;JAMMIN OUT OF HERE IF THERE IS NO DOS LIBRARY!
 MOVE.L D0,A5           ;GET DOS LIBRARY PTR INTO A5

MEASUREREPLY
 JSR LVO.OUTPUT(A5)
 MOVE.L D0,D1
 MOVE.L #THEMESSAGE,D2  ;GET ADDRESS OF THE TEXT (OF THE REPLY!) INTO D2
 MOVE.L D2,A0
 ZERO D3
COUNTLENGTH
 ADDQ.W #1,D3           ;COUNT LENGTH OF REPLY TEXT IN D3
 TST.B (A0)+
 BNE COUNTLENGTH
 ADD.B #10,(A0)         ; APPEND LINEFEED TO STRING (Arnie's modification)
 ADDQ.W #1,D3           ; INCLUDE LINEFEED IN STRING LENGTH

NOWPRINTREPLY
 JSR LVO.WRITE(A5)      ;PRINT REPLY TO THE MESSAGE (A5 IS DOS LIB PTR)

;**************** END OF PROCESSING THE REPLY

EXIT
 MOVE.L A4,D0           ;CLEAN UP IN AN ORDERLY WAY AND EXIT
 BEQ CLOSEDOS           ;IF PORT NOT CREATED DONT KILL IT - MOVE ON
 MOVE.L D0,A0           ;NO NODE/PORT REMOVAL - ITS NOT PUBLIC (NO NAME)
 BSR KILLAPORT          ;SO JUST RETURN PORT MEMORY AND SIGNAL
CLOSEDOS
 MOVE.L A5,D0
 BEQ QUITNOW            ;IF DOS NOT OPENED DONT CLOSE IT
 MOVE.L D0,A1
 SYSCALL CLOSELIBRARY
QUITNOW
 RTS

;*************** GENERAL PURPOSE CREATE AND DELETE MSGPORT ROUTINES

MAKEAPORT        ;ENTER W/ PTR TO NAME IN A0, PRIORITY IN D0
 PUSH D0/A0                        ;STASH THE REGS
 MOVE #-1,D0                       ;DON'T CARE WHICH SIGBIT ALLOCATED FOR PORT
 SYSCALL ALLOCSIGNAL               ;GET A SIGBIT
 MOVE.B D0,D7                      ;STASH SIGBIT IN D7
 CMPI.B #-1,D0                     ;IF ERROR -
 BEQ ERR_PORTNOSIG                 ; BRANCH OUT FROM HERE AND QUIT COLD
 PUBLICMEM #SIZE.MP                ;ELSE ALLOCATE MEM FOR A MESSAGE PORT
 TST.L D0                          ;IF ERROR -
 BEQ ERR_PORTNOMEM                 ; BRANCH OUT FROM HERE AND FREE SIGNAL
 MOVE.L D0,A4                      ;ELSE PUT POINTER TO ALLOCATED MEM IN A4
 ZERO D0
 MOVE.L D0,A1                      ;FOR THIS TASK -
 SYSCALL FINDTASK                  ;FIND THE TASK CONTROL BLOCK
 MOVE.L D0,MP.SIGTASK(A4)          ;TELL PORT WHERE THE TCB IS
 PULL D0/A0                        ;RESTORE THE REGS
 MOVE.L A0,NODE.NAME(A4)           ;TELL LISTNODE OF PORT ITS NAME
 MOVE.B D0,NODE.PRI(A4)            ;TELL LISTNODE OF PORT ITS PRIORITY
 MOVE.B #NT_MSGPORT,NODE.TYPE(A4)  ;TELL LISTNODE OF PORT ITS TYPE
 MOVE.B #PA_SIGNAL,MP.FLAGS(A4)    ;TELL PORT ITS FLAGS
 MOVE.B D7,MP.SIGBIT(A4)           ;TELL PORT WHICH SIGBIT WAS ASSIGNED TO IT
 CMPA.L #0,A0                      ;IF NO NAME
 BEQ.S PRIVATEPORT                 ; THEN ITS A PRIVATE PORT
PUBLICPORT                         ;ELSE IT HAS A NAME AND ITS PUBLIC
 MOVE.L A4,A1                      ;PUT PTR TO MEM OF PORT INTO A1
 SYSCALL ADDPORT                   ;AND ADD THIS PORT TO EXISTING ONES
 BRA NOPORTERR                     ;AND FINISH UP
PRIVATEPORT
 LEA MP.MSGLIST(A4),A0             ;SET UP PORT AS FIRST IN LIST
 NEWLIST A0                        ;SEE MACRO ABOVE
NOPORTERR
 MOVE.L A4,D0                      ;PUT ADDRESS OF MSGPORT IN D0
 RTS                               ;TO MAKE IT EASY TO SEE IF WE FAILED
ERR_PORTNOMEM                      ;IF ONLY NO MEMORY AVAILABLE,
 ZERO D0                           ;FREE THE SIGNAL BIT # ALLOCATED
 MOVE.B D7,D0                      ;BY EARLIER ALLOCSIGNAL CALL
 SYSCALL FREESIGNAL
ERR_PORTNOSIG
 ZERO D0                           ;AND RETURN 0 IF EITHER ERROR OCCURED
 RTS

KILLAPORT       ;ENTER W/ POINTER TO MSGPORT IN A0
; PUSH A0                       ;REMOVES THE PORT/NODE FROM THE SYSTEM LIST
; MOVE.L A0,A1                  ;THIS IS AN ALTERNATIVE!! TO CALLING
; MOVE.L (A1),A0                ;EITHER EXEC REMOVE OR EXEC REMOVEPORT
; MOVE.L NODE.PRED(A1),A1       ;ONLY USED FOR PUBLIC PORTS!!!
; MOVE.L A0,(A1)                ;DONT USE THIS CODE UNLESS PORT IS PUBLIC
; MOVE.L A1,NODE.PRED(A0)       ;THAT IS, IT HAS A NAME AND!! WAS ADDED USING
; PULL A0                       ;ADDPORT.  NO REMOVAL NEEDED FOR THIS EXAMPLE
JUSTKILL
 PUSH A0                        ;STASH THE POINTER ON THE STACK
 ZERO D0
 MOVE.B MP.SIGBIT(A0),D0        ;AND FREE UP THE SIGNAL BIT
 SYSCALL FREESIGNAL             ;PREVIOUSLY ALLOCATED FOR THIS PORT
 PULL A1                        ;AND THE PORT'S MEMORY
 MOVE.L #SIZE.MP,D0
 SYSCALL FREEMEM
 RTS

; DSEG   ; uncomment this line for the Aztec assembler
 DATA    ; and comment out this ones

 CNOP 0,4               ;LONG WORD ALIGN

_DOSNAME
 DC.B 'dos.library',0

 CNOP 0,4

CMDNAME
  DC.B 'REMO',0         ;USE THIS LINE IF YOU WANT TO TALK TO DIGIPAINT3
; DC.B 'JAH',0            ;

 CNOP 0,4

JAHMESSAGE               ;A STRUCTURE OF 20 BYTES SIZE
 DC.L 0                 ;NODE SUCCESSOR POINTER
 DC.L 0                 ;NODE PREDECESSOR POINTER
 DC.B 5                 ;NODE TYPE = NT_MESSAGE
 DC.B 0                 ;NODE PRIORITY
 DC.L CMDNAME           ;THIS GIVES OUR MESSAGE A NAME
 DC.L 0                 ;REPLY PORT PTR (TO PORT CREATED ABOVE)
 DC.W 84                ;MESSAGE LENGTH = 20 + 64 BYTES OF MESSAGE DATA
THEMESSAGE              ;HERE WE PUT THE MESSAGE FROM COMMAND LINE
 DCB.B 64,0

PORTNAME                ;HERE WE PUT THE PORTNAME FROM COMMAND LINE
 DCB.B 16,0
