368 lines
9.3 KiB
Plaintext
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 */
|
|
|