amiga-e/amigae33a/E_v3.3a/Src/Src/Pd/ARexxPort.e

368 lines
9.3 KiB
Plaintext

/* FOLD info
~~~~ */
/* ARexxPort.e 1.0 - by Leon Woestenberg (leon@stack.urc.tue.nl) */
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/*
Here I present some basic functions to make your E programs
capable of communicating with other multitasking programs via
ARexx. With these functions your program can:
· Receive and react to ARexx commands that are sent to it.
· Invoke Rexx Master to run commands that your program does not
understand. This can be an ARexx script (in REXX:) too.
· Send ARexx commands to other programs or to Rexx Master.
This source is public domain, so use it :)
The source is fully commented and is almost self explaining. The
only hard thing is this: When an incoming ARexx message contains
a command that is not supported by your program, this message
is NOT YET REPLIED. First, a NEW message is created that is sent
to Rexx Master. This new message contains a pointer to the first
message. Now, when the new message is replied by Rexx Master, we
can remove the first message from memory (by using the pointer).
In this way, ARexx scripts can transparantly be used with ARexx
commands. Note that the default extension for these script can
be adapted for your program in the sendRexxMsg procedure.
ARexx adds a really nice capability to your multitasking Amiga,
as tasks can interact in realtime with each other, so that they
can use each others features. Think about how your programs can
be extended with a nice ARexx interface.
If you have any questions, suggestions or even bugreports, reach
me via Internet email. More common questions/discussions about
this source are also welcome on the Amiga E mailing list.
Leon Woestenberg (leon@stack.urc.tue.nl)
*/
/* FEND */
/* FOLD "modules" */
MODULE 'exec/ports','exec/nodes'
MODULE 'rexxsyslib','rexx/rexxio','rexx/rxslib','rexx/errors','rexx/storage'
MODULE 'dos/dos'
/* FEND */
/* FOLD "definitions" */
DEF hostport=NIL:PTR TO mp
DEF runflag=TRUE
DEF unconfirmed=0
/* FEND */
/* FOLD "main" */
PROC main() HANDLE
/* open rexx library */
IF (rexxsysbase:=OpenLibrary('rexxsyslib.library',0))
/* create a host port for arexx */
IF (hostport:=createPort('ExampleHost',0))
/* examples of your program sending arexx commands to others
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/*
/* tell GoldED to move cursor up one line */
sendRexxMsg('GOLDED.1','UP',NIL,0)
/* tell the command shell to execute the list command */
sendRexxMsg('REXX','"ADDRESS COMMAND list"',NIL,0)
/* run a script from REXX: (set the default extension in sendRexxMsg) */
sendRexxMsg('REXX','scriptname',NIL,0)
/* send a 'QUIT' command to ourselves :o) */
sendRexxMsg('ExampleHost','QUIT',NIL,0)
*/
/* inform the user we are running */
WriteF('Waiting for events to occur. Send me an ARexx QUIT command by typing:\nrx "ADDRESS \aExampleHost\a; QUIT" from a shell. Or press CTRL-C to break me.\n')
/* wait for events */
wait()
deletePort(hostport)
ELSE
WriteF('Sorry dude, seems like I\am already running once.\n')
ENDIF
CloseLibrary(rexxsysbase)
ELSE
WriteF('Could not open the rexxsyslib.library. I really need it!\n')
ENDIF
EXCEPT
WriteF('Something like \d went wrong, ya see?\n')
deletePort(hostport)
hostport:=NIL
IF rexxsysbase
CloseLibrary(rexxsysbase)
rexxsysbase:=NIL
ENDIF
ENDPROC
/* FEND */
/* FOLD "wait" */
PROC wait()
DEF signalmask=0
DEF hostmask=0
/* signalmask for our host port */
hostmask:=Shl(1,hostport.sigbit)
/* still running or unconfirmed messages? */
WHILE runflag OR unconfirmed
/* wait for event signals */
signalmask:=Wait(hostmask OR SIGBREAKF_CTRL_C)
/* and handle all happened events */
IF signalmask AND hostmask THEN handleRexxMsg()
IF signalmask AND SIGBREAKF_CTRL_C THEN runflag:=FALSE
ENDWHILE
ENDPROC
/* FEND */
/* FOLD "handleRexxMsg" */
PROC handleRexxMsg()
/* pointer to handled message */
DEF rexxmsg:PTR TO rexxmsg
/* pointer to messagenode */
DEF msgnode:PTR TO mn
/* pointer to listnode of message */
DEF listnode:PTR TO ln
/* list of 16 pointers to command strings */
DEF rexxargs:PTR TO LONG
/* points to first char of trimmed command */
DEF command:PTR TO CHAR
/* (another) message in queue? */
WHILE rexxmsg:=GetMsg(hostport)
/* set pointer to messagenode */
msgnode:=rexxmsg.mn
/* set pointer to listnode */
listnode:=msgnode.ln
/* set pointer to commands */
rexxargs:=rexxmsg.args
/* confirmation reply of a message sent by us? */
IF listnode.type=NT_REPLYMSG
/* original message pointer present? */
IF rexxargs[15]
/* reply original message */
ReplyMsg(rexxargs[15])
ENDIF
/* delete this confirmation message */
DeleteArgstring(rexxargs[0])
DeleteRexxMsg(rexxmsg)
/* decrease unconfirmed count */
DEC unconfirmed
/* a brand new message */
ELSE
/* point to command after skipping spaces etc. */
command:=TrimStr(rexxargs[0])
WriteF('We received an ARexx command: \s\n',command)
/* initialize the resultcodes */
rexxmsg.result1:=0
rexxmsg.result2:=NIL
/* example of handling a command that someone sent to us
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/* command known? */
IF StrCmp('QUIT',command,ALL)
WriteF('So let\as quit here.\n')
runflag:=FALSE
ReplyMsg(rexxmsg)
/* command unknown */
ELSE
WriteF('Hmmm. Unknown command. Let\as send it to Rexx Master...\n')
/* forward this command to rexx master (maybe it's a script?) */
/* the original unknown command message is not yet replied to */
/* until we receive a confirmation from rexx master. */
/* therefore we remember this message by storing a messagepointer */
/* in rexxargs[15] of the forwarded command to Rexx Master */
/* message can not be sent to rexx? */
IF sendRexxMsg('REXX',rexxargs[0],rexxmsg,0)=NIL
/* set fatal error returncodes */
xReplyRexxCmd(rexxmsg,RC_FATAL,NIL)
/* reply the message */
ReplyMsg(rexxmsg)
ENDIF
ENDIF
ENDIF
ENDWHILE
ENDPROC
/* FEND */
/* FOLD "sendRexxMsg(hostname,command,unknownmsg,flags)" */
PROC sendRexxMsg(hostname,command,unknownmsg,flags)
DEF arexxport=NIL:PTR TO mp
DEF rexxmsg=NIL:PTR TO rexxmsg
DEF rexxargs:PTR TO LONG
DEF listnode=NIL:PTR TO ln
DEF temp=NIL
/* return if hostport is not present */
IF hostport=NIL THEN RETURN NIL
listnode:=hostport.ln
/* return if we can't make a rexxmessage */
IF (rexxmsg:=CreateRexxMsg(hostport,'rexx',listnode.name))=NIL THEN RETURN NIL
/* pointer to commands */
rexxargs:=rexxmsg.args
/* can we create an argstring? */
IF temp:=CreateArgstring(command,StrLen(command))
/* set the first argstring */
rexxargs[0]:=temp
/* set the flags */
rexxmsg.action:=RXCOMM OR flags
/* store original message pointer into 16th argstring pointer */
rexxargs[15]:=unknownmsg
/* forbid multitasking */
Forbid()
/* send our message to an existing port for sure */
IF (arexxport:=FindPort(hostname)) THEN PutMsg(arexxport,rexxmsg)
/* permit multitasking */
Permit()
/* sended? */
IF arexxport
/* increase the unconfirmed counter */
INC unconfirmed
/* successfully sent this message */
RETURN rexxmsg
ENDIF
ENDIF
IF temp
DeleteArgstring(temp)
ENDIF
IF rexxmsg
DeleteRexxMsg(rexxmsg)
ENDIF
RETURN NIL
ENDPROC
/* FEND */
/* FOLD "replyRexxMsg(rexxmsg,rc,returnstring)" */
PROC xReplyRexxCmd(rexxmsg:PTR TO rexxmsg,rc,returnstring)
/* set the returncode */
rexxmsg.result1:=rc
/* and a pointer to the result string */
rexxmsg.result2:=IF (rexxmsg.action AND RXFF_RESULT) AND (returnstring<>NIL) THEN CreateArgstring(returnstring,StrLen(returnstring)) ELSE NIL
ENDPROC
/* FEND */
/* FOLD "createPort(portname,priority)" */
PROC createPort(portname,priority)
DEF port=NIL:PTR TO mp
DEF node=NIL:PTR TO ln
/* make port public? */
IF portname
/* no-one make the same port please */
Forbid()
/* is our (soon to be) port unique? */
IF FindPort(portname)=0
/* could we make a port? */
IF port:=CreateMsgPort()
node:=port.ln
/* fill in the name */
node.name:=portname
/* public port priority */
node.pri:=priority
/* and make this port public */
AddPort(port)
ENDIF
ENDIF
/* multitask */
Permit()
/* just make private port */
ELSE
/* try to make a port */
port:=CreateMsgPort()
ENDIF
/* return pointer to port, or NIL if the port could not be made (unique) */
ENDPROC port
/* FEND */
/* FOLD "deletePort(port)" */
PROC deletePort(port:PTR TO mp)
DEF node=NIL:PTR TO ln
DEF msg=NIL:PTR TO mn
/* pointer given? */
IF port
node:=port.ln
/* if public then remove from public port list */
IF node.name THEN RemPort(port)
/* no more messages please */
Forbid()
/* remove all messages in queue */
WHILE msg:=GetMsg(port) DO ReplyMsg(msg)
/* delete the port */
DeleteMsgPort(port)
/* multitask */
Permit()
ENDIF
ENDPROC
/* FEND */