home *** CD-ROM | disk | FTP | other *** search
-
- Ever since I started using AREXX, I developed strong ideas on what
- feautures make a Rexx Host. Rather than to simply say what I want, I
- decided to put together an example.
-
- Actually, last year I started adding a bi-directional Rexx port to
- DME. But <.....> had already added a
- a Rexx port, and in a way that was incompatible with my then version.
- So I cancelled my project. Finding nothing else to do during this
- summer, I decided to create an example out of it. Mainly I want to be
- able to say, "If I can do it, so can any programmer". In the meantime,
- I also had the opportunity to look at the proposals of <..............>
- on adding a rexx port to MicroEmacs, and at Tom Rokicki's version of
- FreeDraw.
-
- Now, let me list the levels of Rexx support a program may have:
-
- 1(a). ARexx is a glorified macro processor cum variable handler.
- 1(b). Commands will also be accepted from ARexx.
- However the program does not have both 1(a) and 1(b).
-
- 2. The program exists in two modes: In the active mode, 1(a) is
- supported. In the idle mode 1(b) is supported.
-
- 3. Full bidirectional support is there. [If that is the case, support
- for asynchrnous arexx invocations may also be given.]
-
- Tom's FreeDraw does all three. But I want a few more features:
- Firstly, there should be a way to control the access. My suggestion
- would be to have paswords. External commands must be prefixed with the
- password while the restriction is in effect. Restriction placed by
- the user at the console must take precedence over others.
- No commands must be carried out after the program reaches the
- halt condition: This when the halt command is recieved from the console
- but before the program has cleaned up after itself.
- Anything else that is in this example, but I have forgotten. :-)
-
- ---------------------------------------------------------------------------
-
- USERS' MANUAL FOR testrh
-
- The user interface is crude: After all this is only a "proof of concept".
-
- This program will run only from CLI. The point is that the source code is
- all that is important. You also need arp.library and, of course, the ARexx
- system library.
-
- This program should be invoked as "testrh upw" where upw is any ascii
- string. This string will be used as the password when you "lock" the
- Rexx server. This program then opens a public port named "RDE" and waits.
-
- To send a command to the host, you simply address it to the port.
- To give a command to this program, you first hit Control-D. Then you
- will be prompted for the command. Enter the command and any arguments for
- that command, followed by carriage return.
-
- In the string you enter, the seven characters ()`'\^$ have special meaning.
- Further, ' ' (space) is used as a field seperator. If the argument you
- want to enter contains spaces, enclose that in (): Thus, to enter
- abc xyz
- as a single argument, you will type (abc xyz). These nest: Thus
- ((abc def) (xyz uvw))
- means "(abc def) (xyz uvw)". (abc (def xyz) is illegal. Alternatively, you
- may use `' in place of ().
-
- The character '^' is a prefix that causes the following char to be
- interpreted as a control char: ^a means char '\001'. Backslash (\)
- is the escape char: \^ is the caret, \( is open paran and \\ is the
- backslash. Finally, $ is replaced by a global string variable that
- (usually) contains the result string returned by a Rexx macro.
-
- The following commands can be given from the keyboard:
- quit [no args]
- Close up shop and quit.
-
- lockrh [no args]
- Put the "user lock" on the rexx host. If an external command is
- prefixed by the password set in the command line of the invocation,
- the command will not be executed.
-
- unlockrh [no args]
- removes the user lock.
-
- clrrhlocks [no args]
- Removes the user lock and any lock placed by a Rexx macro.
-
- execute arg
- The arg is passed to AmigaDOS via Execute().
-
- The previous five command are privilaged: They cannot be executed via
- ARexx macros. The rest may executed either from the console or from the
- Rexx port.
-
- set arg
- arg is placed in the string variable $.
-
- show [no args]
- The string in $ is printed in the console window.
-
- rxc arg
- arg is passed to ARexx as a command invocation.
-
- rxo arg1 arg2
- arg2 is passed to ARexx. The manner is controlled by the options
- specified in arg1: arg1 must consist of exactly five characters:
- Thus it must be: (f|.)(r|.)(s|.)(t|.)(a|.) These are interpreted
- as follows: If the last char is 'a', the message is sent
- asynchronously; we will not wait for ARexx to complete the call.
- If the fourth char is a 't', command string tokenization is
- requested from Rexx. If the third char is an 's', the command is
- sent as string file. if the second char is an 'r', a result string
- will be requested. If the first char is an 'f', the invocation is a
- function invocation rather than a command invocation. Further, arg2
- is interpreted in a special way: It is parsed into seperate pieces
- seperated by spaces [unless enclosed in () or `']. There can at
- most 14 such pieces.
-
- Some examples are:
- rxo .rs.. (EXIT TIME()) : Will put the system time into $.
- <.............>
-
- Any other command is considered to be an implicit invocation of an ARexx
- macro.
-
-
- The following commands make sense only from ARexx macros:
-
- LOCK mpw
- This places a macro lock on the Rexx host. Till this lock is
- removed via UNLOCK, or by a clrrhlocks command from the console,
- all external commands must be prefixed by the password given as the
- argument of this command. Note that this lock may be forcibly
- removed by the user. So select mpw to be distinct from any commands
- you may give.
-
- UNLOCK [no args]
- This removes the macro lock.
-
- MSGTOUSR msg
- Prints out the message string msg at the console window.
-
- STRING
- You must request a result string when sending this command. The
- current value of $ is returned as the result string.
-
- Anything other than these four commands will be passed to the general
- command dispatcher to be interpreted the same way as commands from the
- console.
-
- P.S: Both implied invocations of ARexx macros and string file invocations
- set the inital host address to be "REXX". All other invocations set the
- initial address to be "RDE".
-
- ----------------------------------------------------------------
- A short guide to the code
-
- I have tried to make this as easy to reuse as possible. If you want to
- just link this code into your program, with or wothout modifications,
- you need to read this. At best, you can just define some string aliases
- and assemble the support routines. Unfortunately, this assembles only
- with the Manx assembler. It is becuase I am too lazy to make it assemble
- with others. But somebody may wnat to try.
-
- The following global variables must have been initialized somewhere in
- your code.
- RexxSysBase: Pointer to the ARexx system library.
- SysBase: Pointer to the Exec library.
- ArpBase: Pointer to arp library. This is used only to call the
- case-insensitive Strncmp. Change this if you don't want
- to rely on arp.library.
-
- RHPort: Pointer to the message port used to communicate
- with ARexx
- RHFlags: (UWORD) flags on the state of this host. See the .i
- file for the bit definitions.
- ChkPorts: (UWORD) flags to indicate invalid signals for msg ports.
- The bit for RHPort will be set after the end of a
- synchronous invocation.
- CmdErr: (ULONG) Error flags. More serious errors should correspond
- to the higher bits. The severity level is set based on this.
-
- The following global variables are declared in rderxsupp.asm. They may need
- to be modified by you.
-
- RHUsrPassWd: Pointer to the pass word set by the user.
- RHMcrPassWd: Pointer to the pass word set by an external macro
- RHOutCount: No of outstanding messages. Do not exit till this goes to 0.
- RMSeqNo: The serial no of the last msg to Rexx. (modulo 2^16) Can be
- used to keep track of async messages.
-
- The following are constants used.
- rhcmds: This is an array listing the commands to the rexx host. It is an
- array of struct {rhcn *name; int *fn()}
- where rhcn is a struct {UBYTE len; char nm[1]}, with len&127 = length of
- te command name, bit 7 of len is set if this command doesnot return a
- result string; fn is the address of the function to call.
-
- CErc: This is an array of UWORDs listing the return codes corresponding
- to the bits of CmdErr.
-
- The following two functions must exist:
-
- do_command(char *cmdstr):
- This is the general command parser/interpreter. It will be passed
- the command string sent from ARexx (minus the password if any). It must
- not alter its argument. [This is important if you expect to allow external
- commands.]
-
- drm_end(union {int err; char *result} r2, long r1;
- union {ULONG no;void *adr} id)
- This function is called after the return of messages we sent to
- ARexx. The "id" argument is always the id passed to sendrxmsg() when the
- message was sent. The (r1, r2) fields are to be interpreted as follows:
- case (r1 = 0, r2 = 0) : No errors, no result string.
- case (r1 = 0, r2 != 0): No errors; r2.result points at a copy
- of the result string. This
- store must be free()'ed by you.
- case (r1>0) : There was an error. r1 = severity and
- r2 = error code.
- case (r1 = -1) : The macro went ok, but couldn't malloc()
- memory for the result string.
-
- The following routines are avaiable for rexx support:
-
- disprxmsg(struct RxMsg *msg)
- This disposes of rexx messages. If the message is one we sent,
- it releases all allocated resources and then calls drm_end().
- If the message is external, it first checks for Halt condition.
- Then it checks for locks. If there is a lick, the pass word is checked and
- if valid, the command string is extracted. Then it sees if the command
- is rexx-host specific. If so, the correspoding function is called as
- rv = fn(char *arg, char *str, long len)
- Here arg is a pointer to the argument. This string must not be altered.
- The return value is actually composed of rv, str and len. Only the
- following combinations are valid. Any other combination may cause
- memory loss or corruption:
- rv = 0; len = 0; str = NULL: No errors. No result string.
- rv = 0; len != 0; str != NULL: No errors. str points at
- the result string and len is its length. The storage for
- str must have been allocated with malloc() as a call of
- of the form "free(str)" will be made.
- rv != 0; len any; str = NULL: There was error. rv = severity
- level and len = secondary code.
-
-
- sendrxmsg(ULONG act, ULONG flgs, union {long no char *str} args[],
- union {ULONG no; void *adr} id)
- This routine creates and sends messages to ARexx. The arguments to this
- function have the follwoing meaning:
- act : entered as is into rm_Action field.
- act&0x0f will be used as the no of args to be converted.
- must be less than 15, but NOT equal
- flgs: this is a bit field with bits 0:14 being the flags for
- conversion: bit i is 0 => args[i] is a string
- bit i is 1 => args[i] is a long.
- if SRMB_ASYNCH is set, the message is sent asynchornously:
- sendrxmsg will not wait for the message to come back.
- if SRMB_HOSTNM is set, the initial Host will ARexx itself.
- [usually it is ourselves.]
- if SRMB_TONAME is set, the message is sent to the port named
- 'AREXX'. Otherwise it is sent ot 'REXX'. This is valid
- only from v1.10 on. THIS IS NOT TO BE USED AS A COPOUT
- BY THOSE NOT WISHING TO IMPLEMENT ASYNCHRONOUS
- CAPABILITY. [only by those who CAN'T :-)]
-
- args: This is an array 0..14 of union{long ; char *}. Used to
- fill the rexx msg.
- id : This is the message id. Will be entered as is into
- rm_Args[15] field of the rexx message.
- Is passed as an argument to drm_end.
- Return value: 0 --> all ok
- 1 --> too many outstanding messages.
- 2 --> Unable to create the message/argstrings
- 3 --> No public (A)REXX port
-
- The last support routine is rxerrmsg(n): It returns a string containing
- a description of the error with code n. It is basically a fluffed up
- ErrorMsg() call.
-