Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Article on ARexx command hosts

188 views
Skip to first unread message

Eric Giguere

unread,
Sep 3, 1991, 2:29:25 PM9/3/91
to
I've been doing some articles for the AmigaWorld Tech Journal. In issue #4
there will be an article on ARexx function hosts. The article below was
meant to be a sequel for issue #5, however due to scheduling snafus it had
to be dropped. Thus I might as well distribute it on the net... the
programs it refers to are available via FTP from the ARexxLib site
(arexx.uwaterloo.ca = 129.97.208.32) as the file /pub/arexx/rexxhs.lzh.
------------------------------------------------


ARexx Command Hosts
Copyright (c)1991 by Eric Giguere

Permission is granted to distribute the text of the article
providing this notice is left and said distribution is for
non-commercial purposes. The programs accompanying this
article are in the public domain, however, so do what you
want with them.

Last issue we looked at the details involved in implementing
an ARexx function host, which is an application that can
accept function calls from ARexx programs. This month
we'll implement something similar: an ARexx command host,
written in ARexx instead of C. And as an experiment we'll
also write a function host in ARexx. To do all this,
we need some help in the form of a new ARexx function library.
But first let's refresh our memories...

Note: This article assumes you have a basic understanding of
the Amiga's interprocess communication facilities. If not,
please refer to my article in the second issue of the Tech Journal.
Though Amiga shared libraries won't be discussed in much detail,
you might also want to read Jim Fiore's article "Shared Libraries
for the Lazy" from the first issue. More details on the ARexx features
described in this article (including instructions on how to implement
function libraries) can be found in the Amiga Programmer's Guide to ARexx,
available from Commodore-Amiga Technical Support.

Definitions

An ARexx command host (sometimes called a host application)
is simply an application program that accepts and responds to
ARexx command strings. A command string can be sent with the
ARexx ADDRESS instruction:

address 'TURBOTEXT' 'move' line col

Command strings can be declared separately:

address 'AMIGATEX'
'ToFront'
'TeXify' file

In either case, the first argument to the ADDRESS instruction
identifies the application to which commands are to be sent.
The argument is the name of a public message port which the
application has created, often referred to as an "ARexx port".
ARexx sends the command string to this port and waits for
a reply. The reply sets the RC variable (an integer return code)
and in some cases the RESULT variable (a result string).

The messages that are passed between an ARexx program and
a command host is a special structure based on an Exec Message
and known as a RexxMsg. A RexxMsg includes space for a
command string, action flags, and results. (The same structure
is used to send messages to function hosts, though the fields
in the structure are used a bit differently.)

An ARexx function library is a shared library (typically written
in C or in assembler) that adds new functions to ARexx. Like
function hosts, function libraries are added to ARexx's Library List.
When an ARexx program calls a function that is neither internal
to the program or built-in to ARexx, ARexx will search through
the entries in the Library List (ordered by priority) and ask
each function library or function host if it supports the function.
ARexx does this for function hosts by sending a message to an
ARexx port. No message-passing is involved with function libraries:
ARexx loads the library into memory and calls it directly.

ARexx IPC Support

We can't implement a command host without routines for
interprocess communication (IPC) --- creating an ARexx port,
sending messages, and receiving messages. Sending messages
is easily done via the ADDRESS instruction. Managing
an ARexx port is done using routines from the ARexx support
library, a function library that comes with ARexx. To
use functions from the support library, make sure the
rexxsupport.library file exists in your LIBS: directory.
Then execute the following statement from the CLI command line:

rxlib rexxsupport.library 0 -30 0

Alternatively, you could place the following code at the
beginning of any program that uses the support library:

if( ~show( 'l', "rexxsupport.library" ) )then do
if( ~addlib( "rexxsupport.library", 0, -30, 0 ) )then do
say "Could not open rexxsupport.library"
exit 10
end
end

Both of these methods add the support library to ARexx's Library
List, and if you use the support library very often you'll
probably want to add the rxlib call to your Amiga's startup-sequence
file.

Once the support library is installed, creating an ARexx port is
simply a matter of calling the OpenPort() function with the name
of the port as the first argument:

if( OpenPort( "MYPORT" ) = Null() )then do
say "Could not open message port!"
exit 10
end

OpenPort() returns the address of the message port. Compare
the address to the value returned by the Null() function to make
sure a message port was indeed created. Port names are case-sensitive.
Command hosts should always use uppercase letters in their port names.

Addresses in ARexx are four-byte strings that correspond to
a C pointer. These addresses aren't meant to be printed directly.
Use one of the functions C2B(), C2D() or C2X() to print the values.
For example, the line

say c2x( Null() )

would print the string '0000 0000', which is what Null() always
returns.

When you're done with a message port, use the ClosePort() function
to delete it, passing the name of the port as the only argument:

call ClosePort "MYPORT"

ARexx will automatically close all open ports when the program
terminates, but it's a good habit to do it yourself.

You can check to see if a message packet has arrived at your port by
using the GetPkt() function:

packet = GetPkt( "MYPORT" )

If a packet has arrived, it is retrieved from the port and its
address is returned. If no messages are waiting, GetPkt() returns
a null address and will compare true with Null().

If you want to simply wait for a message to arrive at your message
port, use the WaitPkt() function:

call WaitPkt "MYPORT"

The ARexx program will be suspended until one or more messages
arrive. Use the GetPkt() function as described above to retrieve
the messages.

The strings in a packet can be accessed using the GetArg() function.
A RexxMsg packet has sixteen slots for storing strings, numbered 0 to 15.
The command string is always stored in slot 0:

command = GetArg( packet, 0 )

You can ignore the other slots, since ARexx doesn't parse command
strings for you --- that's up to you.

When you're done with a packet, you should reply to the sender
of the packet with a return code and possibly a result string.
The support library includes a Reply() function, but it only allows
the return code to be set. If we want to send a result string
back we need a more flexible function, and that's where the
RexxHS library comes in.

The RexxHS Library

The RexxHS (Rexx Host Support) library is a small function library
you'll find on the diskette. Copy the rexxhs.library file to your
LIBS: directory and then add it to the Library List:

rxlib rexxhs.library 0 -30 0

The RexxHS library adds four new functions to ARexx. The first
three take a message packet address as their only argument. The
ValidPkt() function returns 1 if the address is a valid RexxMsg
structure (that is, it was received by GetPkt() but not yet
replied to) and 0 otherwise. The IsFunctionCall() function
returns 1 if a message packet is a function call, 0 otherwise.
The NumArgs() function returns the number of arguments
(strings stored in slots 1 to 15) in a packet, 0 if there are
no arguments. An ARexx command string has no arguments.

The fourth function, ReplyToCall(), is a replacement for the
Reply() function. It replies to a packet but lets the user
set a result string as well as a return code:

call ReplyToCall packet, 0, "a result string"

The return code must be an integer. The result string will only
be sent back if the return code is zero (no error) and
the calling ARexx program requested a result string by using
the OPTIONS RESULTS instruction before making the call.
If the return code is non-zero, the third argument can
be omitted, but if present it must be an integer and
will be stored in the secondary result field of the packet.

Building an ARexx function library isn't a simple task and
is beyond the scope of this article. Full source code to
the RexxHS library (for both the Manx and SAS C compilers)
can be found on the disk.

A Sample Command Host

We now have all the tools we need to write a command host
in ARexx. Most command hosts are real applications written
in some other language and are there to provide access to
the features of those applications, usually via short
ARexx macros. Our sample host is a bit unusual and doesn't
do anything practical, but it illustrates the concepts very
nicely.

Run the sample host by copying the samplehost.rexx file
from the diskette into your REXX: directory and typing

run rx samplehost

A startup message will be printed and the host will inform
you that it is waiting for messages. You can send it any
message you want by sending a message to the SAMPLEHOST
ARexx port. From the CLI you could type:

rx "address samplehost 'hello there'"

The sample host works like this: it waits for a packet to
arrive, retrieves it, retrieves the command string,
parses the command string, acts on the command, then replies
to the packet. The sample host is dumb --- if it doesn't understand your
command it just prints it to the screen. But it does accept
commands to set and get return codes and result strings --- see
the file samplecalls.rexx for examples. To tell the sample host
to quit, just send it an exit command:

rx "address samplehost 'exit'"

Commands are not case-sensitive.

A Function Host

The samplehost.rexx program can also act as a function host, though
you should do this only as an experiment to familiarize yourself
with function hosts. In particular, you must make sure that
the sample host is added to the Library List at a lower priority
than any of the other libraries it uses, otherwise a deadlock
situation could occur --- see the documentation on diskette for
an explanation.

Final Comments

See how easy it is to write a command host? Even in C it's fairly
straightforward if you use a package like Mike Sinz's SimpleRexx
to send and receive ARexx messages. The hard part is deciding what
commands to support and what their format should be --- consult the Amiga
User Interface Style Guide for some recommendations.

--
Eric Giguere gig...@csg.UWaterloo.CA
Unlike the cleaning lady, I have to do Windows.

0 new messages