Amiga Checkmark

Amiga SimpleRexx Toolkit

by Michael Sinz (MKSoft Development)
Copyright 1985-1999 - All Rights Reserved

Here is the raw AmigaMail article and documentation I wrote for SimpleRexx.  This is included in the SimpleRexx archive.


SimpleRexx

A Simplified Interface into the world of ARexx

ARexx, ARexx, ARexx.  2.0 has ARexx.  So, why and how do I support ARexx?

The "Why?" has been answered elsewhere and that is not what this article is about.  Let it suffice that you should support ARexx within your application.  It is a standard that Commodore is pushing and we hope that all new applications will have ARexx support.

As to the "How?", that is what this article is about.  We understand that your existing software may not currently support ARexx and that some of you may never even have looked at what is needed to support ARexx.  New applications can be designed with ARexx support in mind and, with the advent of the AppShell by David Junod, the work involved to support ARexx is nothing more than what is needed to support the features within you application.  However, existing code may not move into the AppShell easily and you may wish to do a minor upgrade to your application to support ARexx.

SimpleRexx is a set of routines that handle the low-level ARexx work for you in such a way as to have your application work with or without ARexx on the target system.  The goal of SimpleRexx is to make adding at least the minimum level of ARexx support to an application a trivial task.

Working with ARexx

REXX is, at its heart, a string processing language.  Most everything that happens in REXX is in the form of a string; even numbers are passed as ASCII representations in most situations.

The Amiga implementation of REXX, known as ARexx, and is part of Release 2.0 of AmigaDOS.  ARexx has a very complete implementation of the REXX language plus the ability to send and receive control messages from "outside" sources.  ARexx then can operate on them in synchronous fashion.  The messages contain text strings that are then interpreted by ARexx as REXX commands or by the "outside" source (the Application) as its commands.

An application that "supports ARexx" is one that can receive and send ARexx messages.  The messages are, like the REXX language, string based and contain the command string of the operation wanted.

To make this even more interesting, there are ways to send and receive data from ARexx.  The data can come in the message itself or via the ARexx RVI (Rexx Variable Interface).  In either case data can be transferred to and from ARexx.  A complete ARexx supporting application would need to be able to send data to a requesting ARexx program/script and get data from that program.

The following code shows how to use the ARexx support library to send and receive ARexx messages.  It also is a "wrapper" around these functions to provide a simplified interface to ARexx to help promote and simplify the idea of adding ARexx support to your existing applications.

SimpleRexxExample.c is a very simple example of the use of the calls in SimpleRexx.  The test.rexx script is an example script to try running while SimpleRexxExample is running.  It will send commands to SimpleRexxExample in order to control it. test.results is the output of test.rexx.

Overview of Functions

The source to SimpleRexx is a single file.  It is SimpleRexx.c. The header file to that contains the type definitions and prototypes for the functions is in the file SimpleRexx.h.

Functions that are "available" via SimpleRexx are used as follows:

  • rexx_handle=InitARexx(AppBaseName,Extension)
    • This initializes a SimpleRexx context.  The rexx_handle is much like a file handle in that it will be used in all other calls that make use of this SimpleRexx context.  Since all SimpleRexx calls correctly check the rexx_handle before doing work, you do not need to check the return result of this call.  If ARexx is not available on your system, SimpleRexx will just not do anything.
  • port_name=ARexxName(rexx_handle)
    • This function returns a pointer to the name of the ARexx port for your context.  The name is based on the AppBaseName plus an invocation number such that multiple copies of an application can run at the same time.  If you have no ARexx port, it returns NULL.
  • sigmask=ARexxSignal(rexx_handle)
    • This function returns the signal bit mask that is needed for the port that is part of your context.  This should be combined with other signal masks to produce the argument to the Wait() call.  This returns NULL if there is no signal mask.
  • rmsg=GetARexxMsg(rexx_handle)
    • This function returns the next Rexx message that is waiting.  rmsg==NULL if there is no message or ARexx is not around.  rmsg==REXX_RETURN_ERROR if a message sent to ARexx via SendARexxMsg() returns an error.
  • ReplyARexxMsg(rexx_handle,rmsg,result,error)
    • This function replies the ARexx message gotten via GetARexxMsg().  The "result" is a pointer to a result string that is returned via OPTIONS RESULTS in the RESULT ARexx variable.  If you have no result, set this to NULL.  Error is the error severity level.  If this is 0, the result string will be returned, if this is non-zero, the error level will be returned in RC.
  • worked=SendARexxMsg(rexx_handle,string,StringFileFlag)
    • This function sends the string to ARexx.  It sets the default host to the context and sets the RXFB_STRING bit in the message if the "StringFileFlag" is set. This routine returns FALSE if the message was not sent for some reason.
  • worked=SetARexxLastError(rexx_handle,rmsg,ErrorString)
    • This function uses the RVI (Rexx Variable Interface) to set a variable named .LASTERROR to the ErrorString.  This is where the "error" message should go if there is an error.  This function returns FALSE if this fails for any reason.
  • FreeARexx(rexx_handle)
    • This closes a SimpleRexx context.  The rexx_handle is one that was gotten from InitARexx().  The routine is fully error checked so that you can pass it a NULL and it will do nothing.  This is useful if you want to just blindly use the rexx_handle.

/*
 * This is an example of how to use the SimpleRexx code.
 */

#include        <exec/types.h>
#include        <libraries/dos.h>
#include        <libraries/dosextens.h>
#include        <intuition/intuition.h>

#include        <proto/exec.h>
#include        <proto/intuition.h>

#include        <rexx/storage.h>
#include        <rexx/rxslib.h>

#include        <stdio.h>
#include        <string.h>

#include        "SimpleRexx.h"

/*
 * Lattice control-c stop...
 */
int CXBRK(void) { return(0); }  /* Disable Lattice CTRL/C handling */
int chkabort(void) { return(0); }  /* really */

/*
 * The strings in this program
 */
char *strings[]=
{
        "50: Window already open",              /* STR_ID_WINDOW_OPEN */
        "101: Window did not open",             /* STR_ID_WINDOW_ERROR */
        "50: No Window",                        /* STR_ID_WINDOW_NONE */
        "80: Argument error to WINDOW command", /* STR_ID_WINDOW_ARG */
        "100: Unknown command",                 /* STR_ID_COMMAND_ERROR */
        "ARexx port name: %s\n",                /* STR_ID_PORT_NAME */
        "No ARexx on this system.\n",           /* STR_ID_NO_AREXX */
        "SimpleRexxExample Window"              /* STR_ID_WINDOW_TITLE */
};

#define STR_ID_WINDOW_OPEN      0
#define STR_ID_WINDOW_ERROR     1
#define STR_ID_WINDOW_NONE      2
#define STR_ID_WINDOW_ARG       3
#define STR_ID_COMMAND_ERROR    4
#define STR_ID_PORT_NAME        5
#define STR_ID_NO_AREXX         6
#define STR_ID_WINDOW_TITLE     7

/*
 * NewWindow structure...
 */
static struct NewWindow nw=
{
        97,47,299,44,-1,-1,
        CLOSEWINDOW,
        WINDOWSIZING|WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE|SIMPLE_REFRESH|NOCAREREFRESH,
        NULL,NULL,
        NULL,
        NULL,NULL,290,40,-1,-1,WBENCHSCREEN
};

/*
 * A *VERY* simple and simple-minded example of using the SimpleRexx.c code.
 *
 * This program, when run, will print out the name of the ARexx port it
 * opens.  Use that port to tell it to SHOW the window.  You can also
 * use the ARexx port to HIDE the window, to READTITLE the window's
 * titlebar, and QUIT the program.  You can also quit the program by
 * pressing the close gadget in the window while the window is up.
 *
 * Note: You will want to RUN this program or have another shell available such
 *       that you can still have access to ARexx...
 */
void main(int argc,char *argv[])
{
short   loopflag=TRUE;
AREXXCONTEXT    RexxStuff;
struct  Window  *win=NULL;
ULONG   signals;

        if (IntuitionBase=(struct IntuitionBase *)
                                        OpenLibrary("intuition.library",NULL))
        {
                /*
                 * Note that SimpleRexx is set up such that you do not
                 * need to check for an error to initialize your REXX port
                 * This is so your application could run without REXX...
                 */
                RexxStuff=InitARexx("Example","test");

                if (argc)
                {
                        if (RexxStuff) printf(strings[STR_ID_PORT_NAME],
                                                        ARexxName(RexxStuff));
                        else printf(strings[STR_ID_NO_AREXX]);
                }

                while (loopflag)
                {
                        signals=ARexxSignal(RexxStuff);
                        if (win) signals|=(1L << (win->UserPort->mp_SigBit));

                        if (signals)
                        {
                        struct  RexxMsg         *rmsg;
                        struct  IntuiMessage    *msg;

                                signals=Wait(signals);

                                /*
                                 * Process the ARexx messages...
                                 */
                                while (rmsg=GetARexxMsg(RexxStuff))
                                {
                                char    cBuf[24];
                                char    *nextchar;
                                char    *error=NULL;
                                char    *result=NULL;
                                long    errlevel=0;

                                        nextchar=stptok(ARG0(rmsg),
                                                                cBuf,24," ,");
                                        if (*nextchar) nextchar++;

                                        if (!stricmp("WINDOW",cBuf))
                                        {
                                                if (!stricmp("OPEN",nextchar))
                                                {
                                                        if (win)
                                                        {
                                                                error=strings[STR_ID_WINDOW_OPEN];
                                                                errlevel=5;
                                                        }
                                                        else
                                                        {
                                                                nw.Title=strings[STR_ID_WINDOW_TITLE];
                                                                if (!(win=OpenWindow(&nw)))
                                                                {
                                                                        error=strings[STR_ID_WINDOW_ERROR];
                                                                        errlevel=30;
                                                                }
                                                        }
                                                }
                                                else if (!stricmp("CLOSE",nextchar))
                                                {
                                                        if (win)
                                                        {
                                                                CloseWindow(win);
                                                                win=NULL;
                                                        }
                                                        else
                                                        {
                                                                error=strings[STR_ID_WINDOW_NONE];
                                                                errlevel=5;
                                                        }
                                                }
                                                else
                                                {
                                                        error=strings[STR_ID_WINDOW_ARG];
                                                        errlevel=20;
                                                }
                                        }
                                        else if (!stricmp("READTITLE",cBuf))
                                        {
                                                if (win)
                                                {
                                                        result=win->Title;
                                                }
                                                else
                                                {
                                                        error=strings[STR_ID_WINDOW_NONE];
                                                        errlevel=5;
                                                }
                                        }
                                        else if (!stricmp("QUIT",cBuf))
                                        {
                                                loopflag=FALSE;
                                        }
                                        else
                                        {
                                                error=strings[STR_ID_COMMAND_ERROR];
                                                errlevel=20;
                                        }

                                        if (error)
                                        {
                                                SetARexxLastError(RexxStuff,rmsg,error);
                                        }
                                        ReplyARexxMsg(RexxStuff,rmsg,result,errlevel);
                                }

                                /*
                                 * If we have a window, process those messages
                                 */
                                if (win) while (msg=(struct IntuiMessage *)
                                                        GetMsg(win->UserPort))
                                {
                                        if (msg->Class==CLOSEWINDOW)
                                        {
                                                /*
                                                 * Quit if the close gadget...
                                                 */
                                                loopflag=FALSE;
                                        }
                                        ReplyMsg((struct Message *)msg);
                                }
                        }
                        else loopflag=FALSE;
                }
                if (win) CloseWindow(win);

                FreeARexx(RexxStuff);
                CloseLibrary((struct Library *)IntuitionBase);
        }
}

Quantum Physics: The dreams that stuff is made of. -- Michael Sinz

Michael Sinz -- Starting Startups

Best viewed with any browser
There have been  Counter  visitors to this page.