home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
291.lha
/
RexxFunctionHostPack_v1.2
/
RexxFuncHost.doc
< prev
next >
Wrap
Text File
|
1992-09-02
|
12KB
|
303 lines
-------------------------------------------------
| |
| Rexx Function Host Package |
| Version 1.2 |
| 02-Sep-89 |
| |
| |
| |
| Copyright © 1989, Donald T. Meyer |
| |
-------------------------------------------------
The Rexx Function Host Package, hereafter abreviated as FHP, is a 'C'
source code module which facilitates writing function hosts for ARexx.
The intent of this document is to give some background on ARexx function
hosts, and then describe how the FHP handles the implementation of them.
The FHP will handle most of the details involved in writting your own
function host.
The code in "rexxfunchost.c" can be modified if desired, but what was
intended is a module that can be compiled once and then linked into any
and all function hosts that you write.
In most cases, the code in "rexxfunchost.c" can be used as is, with the
specific routines you write to handle ARexx function invocations
contained in a seperate module or modules (i.e. "rh_demo.c").
ARexx and External Functions
ARexx has the ability to use external functions contained either in a
standard Amiga shared library, or in a special program called a
function host. Either of these must be specialy written for use with
ARexx. You cannot directly use a "normal" library, such as
icon.library, intuition.library, etc.
For ARexx to "know about" a library or function host, you must first
add it to a special list kept by ARexx, the Library List. This can be
done either by issuing a command from the CLI, or via a function from
within an ARexx program. Once the library or function host has been
added to the ARexx Libray List, whatever functions they contain will
then be available to ARexx programs.
The function host is responsible for function "binding". ARexx passes
a message to the function host, which then performs an internal search
for the desired function name. If that function is contained within the
host, it is called to handle the function's activitys.
Function Hosts vs. Librarys
Using either a function host or a library will achieve almost the same
end result: adding new function calls to ARexx. There are some fairly
major differences however.
Disadvantages: Calls are not easily made reentrant
Must be explicitly run
Advantages: Easier to debug
Inherent call queueing
Individual stack
Individual priority
Asynchronous operation possible
First, the disadvantages.
Consider what happens if two ARexx programs call the same external
function at the same time. In a properly written library, both will
execute at the 'same' time. In a function host, the first one that
makes the call will get the use of the function host, and the second
call will have to wait until the first completes. Although it would be
possible to start a task to handle each function called, if multiple
calls need to execute simultaneously, a library would probably be a
better choice in this case.
A function host must be explicitly executed prior to being accessed.
This would normally be done in the startup-sequence script. A library
must merely reside in the LIBS: directory. On the other hand, the
library is subject to being removed from memory if not open, whereas a
function host is not. This could actually be an advantage depending on
the circumstances.
Now, the advantages which a function host has over a library.
From a 'C' and source-level debugger standpoint, function hosts are
easier to debug since they are essentially just normal programs, happily
recieving messages and returning them.
If you wish to do things which may require interaction with the user
other than through just calling a function, such as allowing the user to
manipulate a scrollgadget for things displayed
via calls to the function host.
If the functions are such that only one ARexx program could use them at
a time, the function host provides an inherent locking and queueing
mechanism. This is due to the fact that function requests arrive as
messages, which are automaticly queued by Exec. A typical example of
something non-shareable would be a hardware device such as a printer.
When a library function is called, the stack used is the caller's.
Since a function host is a totally seperate processs, the stack used is
it's own. This also applies to process priority, although this is
fairly easy to adjust "on the fly" if needed.
Another possible benefit of being a seperate process, is that of
asynchronous execution. A function host can be written such that it
returns the message back to ARexx before the desired function actions
have been taken.
Although most of the advantages provided by a function host can be
incorporated into a library through clever programming, they happen
"naturally" in the function host. Even if the desired end result is a
function library, implementing a function host for ease of testing may
still be worthwhile.
What a Function Host Does
A typical function host will perform the following steps:
1) Start executing, normally as a detached background task.
2) Open neccessary libraries, allocate needed memory, etc.
3) Open a public Exec message port.
4) Wait for a RexxMsg message from ARexx.
5) Dispatch the function call.
6) Process the function call.
7) Return the message to ARexx.
8) Wait for the next message...
9) Cleanup and exit.
Here are the details about what the code in "rexxfunchost.c" does to
perform the above steps.
1) Start executing, normally as a detached background task.
Invocation can be from either CLI or WorkBench. We probably want a
specific stack size and execution priority. If we are launched by the
Workbench, the icon .info file can contain the desired stack size.
This does not help us on priority, though we can change that "manualy"
by making an exec library call. But from CLI, we would wind up with
whatever stack the CLI defaulted to, and we would also prevent that CLI
from accepting further command until we ended our execution.
Lattice and Manx 'C' address these problems quite handily with startup
code which detaches us from the CLI. *** what _exactly_ happens from
workbench with cback.o? *** This startup code allows us to explicitly
request our stack size, priority, and also frees the CLI for further
command entry. There are some slight differences in the way Lattice and
Manx handle this. The FHP is written for Lattice, but should compile
under Manx with minor changes.
If there is already an instance of this function host running, some
additional actions must take place. If launched from the WorkBench we
assume that the reason our icon has been double-clicked again is to
remove the function host. To do this, we send a break signal to our
"twin", and then exit ourselves. To cause this to happen from the CLI,
we must use a command line option "-q" to cause the termination of an
existing "twin". The FHP handles all the logical decisions involved in
deciding what to do, and displays appropriate messages telling the user
what is being done. These messages are defined in your code, so as to
allow easy control of just what is displayed.
2) Open neccessary libraries, allocate needed memory, etc.
The FHP always opens the rexx library. A call is then made to a
function named client_init() which should be in your code. This is the
place to do any initialization required by the functions in your
function host. Returning a pointer to a string will cause it to be
displayed, and the FHP to abort. A NULL return indicates success.
3) Open a public Exec message port.
This is the way that ARexx will send function calls to function hosts.
This must be a public port, so that ARexx can FindPort() it dynamicly as
it searches the Library List.
At this point, the FHP will also automaticly add itself to the ARexx
Library List. This is done by sending a message to the ARexx resident
process. The FHP will also handle removing itself from this list when
it terminates.
4) Wait for a RexxMsg message from ARexx.
With all setup operations complete, the FHP now Wait()s for one of two
events. Upon recieving a function invocation message at the public
port, it will proceed to process the function call. The other event
which will wake up the FHP is the ctrl-C break signal. This signal will
normally be sent by another invocation of this function host, although
it can be sent via Signal() from any Amiga task.
In the 1.2 release of this module, a ULONG variable client_event_flags has
been added. This will allow client code to set events it needs to Wait()
on as well. A client even will result in a call to the
client_event_handler() function, which should be in the client code.
5) Dispatch the function call.
When a function invocation message is recieved, the FHP will handle
several of the details. First and foremost, the FHP code will determine
whether or not the function being called is in our function host. It
does this based on parameters stored in the array func_table. This
array, which is defined in your code, contains four parameters for each
function which control how the FHP handles the function dispatching.
First, the name of the function is defined, followed by the address of
the 'C' routine which will perform this function's actions.
Next, a numeric parameter which specifys how many arguments this
function call should have. If the number of arguments passed in the
ARexx function call is incorrect, the FHP will return an error to
ARexx. This can also be set to -1 to indicate that the FHP should
perform no checking of the parameter count.
And last, a boolean flag indicating whether or not this function name
is case-sensitive or not. If the case flag is set to FALSE, than case
will be ignored when searching for the function name.
Once the FHP has determined that the desired function is here, and that
the parameter count is correct, whatever 'C' routine you have written
to handle the function is called, with a pointer to the rexxmsg as the
sole argument.
6) Perform the function
The function handler routine in your code is passed a pointer to a
RexxMsg structure. Using this pointer, the arguments to the function
(if any) can be accessed, and proper return code or value can be set.
The arguments are passed as pointers to strings. These pointers are in
the RexxMsg structure member rm_Args[]. There can be 15 arguments
passed here (argument 0 is a pointer to the function name itself).
These arguments are accessed thusly: rexxmsg->rm_Args[1]
The details of how arguments are passed and results returned are
contained in the ARexx manual. The example functions in "rh_demo.c"
demonstrate recieving basic arguments, and returning both errors and
result strings.
To ease the task of returning a value string to ARexx, a helper
function is included in the FHP. This function, SetResultString(), takes
a pointer to a RexxMsg (which should of course be the one passed from
the FHP initialy) and a pointer to a string. This function will then
allocate the RexxArg and place it into the RexxMsg structure. If a
NULL is given as the string pointer (not to be confused with a null
string!), a general failure code will be set in the RexxMsg structure.
An error will also be set if the allocation of the RexxArg fails.
This should happen only in cases of low or fragmented system memory.
7) Return the message to ARexx.
Upon returning from your 'C' routine, the FHP will return the message to
ARexx and wait for the next function call to arrive.
8) Wait for the next message...
Loop back to step #4. The FHP stays in this loop until a Control-C break
signal is recieved.
9) Cleanup and exit.
This step is reached upon recieving the termination signal. Again, a
function defined in your code, client_cleanup() is called. This is where
any libraries opened, memory allocated, etc. by the call to
client_init() should be closed or freed.
NOTE: This routine will be called regardless of the reason for the FHP's
exiting. Your cleanup routines should be prepared to be called before
or after client_init() has executed.