home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fish 'n' More 2
/
fishmore-publicdomainlibraryvol.ii1991xetec.iso
/
fish
/
libraries
/
rexxlib_393
/
rexxlib.doc
< prev
next >
Wrap
Text File
|
1990-10-28
|
19KB
|
401 lines
rexxapp.library doc file
1) What is rexxapp.library
2) Opening rexxapp.library
3) The RexxData structure
4) Initializing the RexxData structure
5) Setting up the Rexx interface
6) Receiving Rexx commands
7) Sending Rexx commands
8) Closing down the Rexx interface
««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
1) What is the rexxapp.library
The rexxapp.library is a shared library that can be opened (just like
Intuition) and used by an application to implement an ARexx interface. ARexx
is a script language that can control and facilitate communication between
Rexx capable programs. By providing your application's own set of "Rexx
commands" and attaching a routine to each command, this allows a user to
write a script file to automatically control various aspects of your program.
Also, the user can tie your program to another Rexx capable program, thus
creating an integrated package of the 2 or more products.
This library allows an application to both accept asynchronous REXX messages
and request REXX service. This means that you can use the lib to accept control
from some other application, or use the lib to control another application.
The library handles all of the rexx port and message allocation. It handles
setup as well as deciphering whether a Rexx communication resulted in an error
or success. It keeps track (and frees) all Rexx-related allocated resources.
In short, it completely manages almost all of the Rexx communication on your
behalf via just a half-dozen, easy-to-use functions. The only thing that you
have to do is provide the set of commands that you wish your program to "under-
stand", write the functions to implement those commands, and provide an error
message display routine.
««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
2) Opening rexxapp.library
The rexxapp.library should be copied to the LIBS: drawer of your boot disk.
This lib uses the rexxsys.library which is part of the ARexx product available
from Bill Hawes. This library must be available, and the Rexx interpreter must
be started via RexxMast (also part of the ARexx package). You open the
rexxapp.library via a call to Exec's OpenLibrary(). The current version is 0.0
«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
3) The RexxData structure
The library operates upon what I've defined as a RexxData structure. Certain
fields of this must be initialized once before you setup your Rexx interface
and start calling library functions. All library functions will be passed a
pointer to (ie the address of) this data structure.
Here is the structure definition in C. Note that this structure will have
a different number of imbedded CmdEntry structures depending upon how many
"commands" your program understands. For this reason, you will need to modify
the varible NUMCMDS for your application.
#define NUMCMDS 1
struct RexxData {
struct MsgPort RexxPort;
CHAR *Exten;
APTR Func;
struct *RxsLib; /* defined in the ARexx rxslib.h file */
APTR Error;
APTR Result;
ULONG RexxMask;
ULONG UserData; /* to be defined by and used by the application */
/* The command list goes here. It consists of one CmdEntry structure for
each "command" that the application supports. Note that the number of
commands (and therefore the size of the RexxData) will depend upon how
many "commands" the application supports. This list must end with a
NULL entry.
*/
struct CmdEntry AsscList[NUMCMDS];
};
struct CmdEntry {
char *CmdString;
APTR CmdHandler; /* The return value depends upon what the app's Dispatch
function wants to see returned. */
};
Here is the structure in assembly. Fields that will be initialized by the
application have a bracketed comment indicating what value must be placed in
that field. All other fields will be initialized by the lib.
RexxData:
;---The imbedded port
RexxPort:
dc.l 0,0
dc.b 4,0
dc.l 0
dc.b 0
dc.b -1 ;This is negative (bit 7 set) whenever our port isn't set up
dc.l 0
dc.l RexxData+24
dc.l 0
dc.l RexxData+20
dc.b 0 ;DO NOT ALTER THESE LAST 2 BYTES OF THE PORT
dc.b 0
;---
Exten dc.l [the address of the extension string]
Func dc.l [the address of the dispatch function]
RxsLib dc.l 0 ;the address of rexxsys.library (DO NOT ALTER)
Error dc.l [the address of the Error function]
Result dc.l [the address of the Result function]
RexxMask dc.l 0 ;the mask of the rexxPort's SigBit (to be used by the app to Wait())
UserData dc.l [for the application's use (UserData)]
;---The command association list
[a series of pointers to a null-terminated "command" string followed by
the address of its handler]
dc.l [0] ;The association list must end with a 0 LONG
«««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
4) Initializing the RexxData structure
You must initialize certain fields before calling the lib function,
SetRexxPort(). SetRexxPort() will initialize and setup the other fields
including the imbedded RexxPort. The fields that you must setup are as follows
Exten:
This is a pointer to (ie the address of) a null-terminated string describing
the desired filename extension for Rexx macros invoked by the application.
If not 0, any `primitive' not in the association command list will be sent
out to ARexx for interpretation, thus allowing macro programs to work just
like primitives. If you do not want this behavior, supply a 0 here, and those
commands not specified in your association list will be sent back to ARexx
with an error value of 30. It should be noted that extension should point to
a nulled string if no particular extention is desired, but you want this
feature enabled.
Func
This is a pointer to the application's Dispatch function. This function
will be called by the library ONLY when the application calls ReceiveRexx().
ReceiveRexx() handles all RexxMsgs received from other applications as well
as processing returned RexxMsgs that your program sent out. This function is
called when ReceiveRexx() gets some other program's RexxMsg which has a
command that your program understands (ie is in your association list).
This function is called with 3 arguments--- the Rexx message that was
received, the appropriate command association CmdHandler (ie the handler to
be called from your Dispatch function), and the Argstring (ARG0) stripped of
the command. This function should return a 1 if the message is to be replied
to by the lib or a 0 if not. If not, the application itself is responsible
for replying the message later via Exec's ReplyMsg(). Otherwise, the library
ALWAYS takes care of properly replying all messages. Unless you need to hold
onto a Rexxmsg and consequently "put the Rexx script to sleep" until you
reply it later, you'll let the lib take care of replies. Also, your Dispatch
function should setup the return values with SetupResults() before exiting.
BOOL Func(RexxMsg, CmdHandler, Argstring, RexxData);
d0 a2 a3 a4 a5
Error
This routine is called by the lib when any RexxMsg that the application
created and sent out is returned with an error. It is passed an appropriate
error message, and the error code. Typically, this routine needs to do
nothing more than print the message for the user. You must supply at least
a dummy routine. Do not alter the passed, null-terminated string!
void Error(Code, String, Rexxmsg, RexxData);
d0 a0 a2 a5
Result
This routine is called by the lib when any RexxMsg that the application
created and sent out is returned successfully. It is passed any returned
Result string, and the Result1 code. This routine may do various things with
the Result1 string or code depending upon which function initially sent the
message out. Or, if your application has no use for returned strings, it
could simply be a dummy function. You must supply at least a dummy routine.
Do not alter the passed, null-terminated string!
void Result(Code, String, Rexxmsg, RexxData);
d0 a0 a2 a5
You must also supply the command association list. This is simply a series of
CmdEntry structures, one for each REXX command that the application defines.
The CmdString must be null-terminated and all letters in LOWER CASE (use no
imbedded spaces)! The CmdHandler must point to the routine to execute for this
command. Note that when the lib checks received RexxMsgs, the msgs rm_Arg
string need only be a prefix of one of your commands in order to match.
(ie if one of your commands is "blort", then receiving "Blo" would match.)
There must be a 0 LONG at the end of your command association list. In C,
this can be done by having a NULL CmdEntry at the end. See the example.
««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
5) Setting up the Rexx interface
After obtaining a RexxData structure and initializing the above mentioned
fields, call SetRexxPort(). Your Rexx interface is now setup. Note that
SetRexxPort could fail, so check the return.
***************************** SetRexxPort() *****************************
This is the routine that sets up the REXX (communication) port. It should
be called once before using any other routines.
SYNOPSIS
waitMask = SetRexxPort(portName,RexxData)
d0 a1 a5
INPUT
portName is the desired null-terminated name of your application RexxPort.
This will be used with the ADDRESS command in Rexx scripts written to
control your program. This should be in a buffer that is ONE BYTE LARGER
THAN THE DECLARED NAME. When installing your Rexx port, the lib first
checks to see if there is already some program using this port name. (There
can't be two programs with the same port name.) If so, this function
appends a "2" onto the port name and tries this name. (That explains the
need for your portname buffer to have an extra byte.) So if your portname
is "Blort" and you run 2 copies of your program simultaneously, the first
copy's portname is "Blort", and the 2nd copy's is "Blort2". A third copy
would have a portname of "Blort3". The library can only resolve up to 9
multiple copies.
RETURN
SetRexxPort() returns the signal bit mask to wait on for Rexx messages. This
can be OR'ed with other signals which your program waits for. This value is
also stored in the RexxData's RexxMask field.
If something goes wrong, it simply returns a 0 (z-flag set).
««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
6) Receiving Rexx commands
You should place a call to ReceiveRexx() within your IDCMP loop. If any
Rexx messages have been received, this will cause your Func (dispatch) routine
to be called if this message was sent by some other program (with a command
that your application understands). If the msg is a reply of one that you
sent out, the lib will determine whether there was an error, or if it executed
successfully. If an error, your Error routine is called. If success, your
Result routine is called.
*************************** ReceiveRexx() ********************************
Dispatches all REXX messages that the app might have received. It also frees
up any returned RexxMsgs that the app itself sent out. This function is fast
if no messages are outstanding, so it can be called fairly often from an
IDCMP loop. This function may call the application's Result and Error vectors
in the case of a returned message that was sent out by the application. In
the case of a received Rexxmsg from someone else, it will call the applica-
tion's Dispatch function after parsing for a match in the association
list.
SYNOPSIS
ReceiveRexx(RexxData)
a5
RETURNS
None
Note that when some other application sends you a Rexx message, you do not
need to reply the message (unless your dispatch Func returns 0). The lib does
this for you. You will need to set the returned Result1 and Result2 fields.
You do this using SetupResults(). This function allows you to pass returned
Argstrings to the other application.
***************************** SetupResults() *****************************
Use this function to pass back return codes or a return string when replying a
received REXX msg.
SYNOPSIS
SetupResults(primary, secondary, string, RexxMsg, RexxData)
d0 d1 a0 a1 a5
INPUTS
RexxMsg is the address of the REXX message you are replying.
primary and secondary are the return codes to be stored in the msg's
rm_Result1 and rm_Result2 fields respectively.
string is a null-term return string. This string is only sent to ARexx if
the primary return code is 0, and a string was requested (i.e. the Rexxmsg's
rm_Action field has its RXFB_RESULT bit set). If you have no string to pass
back, pass a 0.
RETURNS
None
««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
7) Sending Rexx commands
There are 3 functions to create and send Rexxmsgs. Two are higher level, and
one is a lowel level routine. All 3 return a pointer to a RexxMsg created to
send your command to Rexx, or 0 if an error. In the case of an error, a pointer
to a null-terminated error message is returned as well. C programmers get this
message from the global RexxErrMsg (in the RexxInterface.asm module), and asm
programmers receive the address of the string in a0.
*************************** SendRexxCmd() ****************************
This is the general ARexx command creation interface, but is not the one that
you will use most of the time; SyncRexxCmd and AsyncRexxCmd are easier to
understand and use.
SYNOPSIS
RexxMsg = sendRexxCmd(rm_Action, InitFunc, string, retFunc, Rexxmsg, RexxData)
d0 d0 d1 a0 a1 a2 a5
INPUTS
rm_Action is the desired ARexx Msg's command invocation field, such as RXCOMM
string is the address of a null-terminated command string to send to Rexx.
Upon return from this function, you may dispose of the string.
retFunc is either NULL, indicating that the command should execute
asynchronously, or the address of a function to be called when the
message we build up and send out here finally returns. Please note
that the function supplied here could be called during cleanup after
a fatal error, so make sure that it is "safe". This function always is
passed 3 args, the RexxMsg that is being replied (a0) and the rm_Result1
and rm_Result2 fields in (d0/d1). Return FALSE to abort, or TRUE to continue.
If retFunc is not 0, then you must also pass the address of the Rexxmsg
which caused this new (asyncronous) command invocation.
InitFunc is the address of an application routine that will be called with
the new RexxMsg. This can be used to further initialize the RexxMsg
(ie set up its rm_Args fields) before the msg is actually sent out. The lib
reserves the last 2 ARGS fields (ARG[14] and ARG[15]), so you must not
alter these. If InitFunc is 0, then just the default initialization is done.
The lib always initializes all fields including the RexxMsg's rm_Action,
ARG[0] command string, rm_Passport, rm_CommAddr, Stdin, Stdout, and node
before calling your InitFunc. This function should return 0 if all went ok,
or a pointer to some error message for abort. Note that you can use the
RexxMsg's ARG[1] to ARG[13] fields for your own use, but you are responsible
for freeing any argstrings that you stuff into these fields (do this in your
Error/Result routines. (You could use these fields for storing things besides
argstrings.)
errormsg = InitFunc(RexxMsg, RexxData);
d0 a2 a5
RETURNS
If all goes well, it sends the message to Arexx and returns the RexxMsg
address. In the case of error, it returns 0 (z-flag set). A null-term error
msg string is also returned. Note that you should check the return code to
make sure that your message got out!
If you have too many msgs currently out (>256), this fails.
Also, if any of the following checks fail, it fails:
- the application has a rexx port open (ie SetRexxPort succeeded)
- Rexx is out there (ie the user started up the Arexx server)
- the rexxsys library opened
- the lib can create a Rexx message
- the lib can create an argstring (for the command string)
***************************** SyncRexxCmd() ******************************
This functions as a synchronous Rexx call. As soon as the action invoked here
returns, we reply to RexxMsg, passing the return codes back. Returns the addr
of the created RexxMsg if success or 0 if an error in sending out the RexxMsg
(z-flag set). The pointer to a null-term error string is also returned in a0
in the case of error. It sends the message with rm_Action = RXCOMM.
SYNOPSIS
RexxMsg = SyncRexxCmd(string, RexxMsg, RexxData)
d0 a0 a2 a5
RETURNS
See SendRexxCmd()
***************************** ASyncRexxCmd() ******************************
This function is used to send out an ARexx message and return immediately.
Its single parameter is the null-term command string to send. Returns the addr
of the created RexxMsg if success or 0 if an error in sending out the RexxMsg.
(z-flag set). The pointer to a null-term error string is also returned in the
case of error. It sends the message with rm_Action = RXCOMM.
SYNOPSIS
RexxMsg = ASyncRexxCmd(string, RexxData)
d0 a0 a5
RETURNS
See SendRexxCmd()
««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
8) Closing down the Rexx interface
You should call FreeRexxPort(), and then close the rexxapp.library.
****************************** FreeRexxPort() ****************************
This function closes down the Rexx port. It MUST be made a part of your
cleanup routine after you have called SetRexxPort(). It removes the
Rexxport, replies to any remaining messages and insures that we get replies to
all the ones we sent out, closes the Rexx system lib, and frees any other
resources. Note that if we haven't received all of our own Rexxmsgs back, this
routine waits until we do.
SYNOPSIS
FreeRexxPort(RexxData);
a5
RETURNS
None