home *** CD-ROM | disk | FTP | other *** search
-
- 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.
-
-