{ARexxBox

{ARexx Interface Design Tool

{Version 1.11

Copyright © 1992,1993 Michael Balzer Oberon-2 source copyright © 1993 hartmut Goebel

Permission is granted to copy and distribute this document as long as the copyright notes and this permission remain unchanged throughout all copies.

No guarantee of any kind is given that the programs described in this document are 100% reliable. You are using this material at your own risk. The authors can not be made responsible for any damage which is caused by using these programs.

This package is freely distributable, but still copyright by Michael Balzer. This means that you can copy it freely as long as you don’t ask for a more than nominal copying fee. This fee must not be more than US $5 or 5 DM.

This limit applies to German Public-Domain dealers too!!

Permission is granted to include this package in Public-Domain collections, especially in Fred Fishs Amiga Disk Library (including CD ROM versions of it). The distribution file may be uploaded to Bulletin Board Systems or FTP servers. If you want to distribute this program you must use the original distribution archive ‘ARexxBox111.lha’.

The authors would like to see this packet included in any kind of developer’s tool chest (e.g. the Native Developer’s Upgrade Kit by Commodore), but please tell us if you do so.

None of the programs nor the source code (nor parts of it) may be used on any machine which is used for the research, development, construction, testing or production of weapons or other military applications. This also includes any machine which is used for training persons for any of the above mentioned purposes.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

1 Important remarks

Before you do anything else: ARexxBox is a tool by programmers for programmers. If you’re a user, this program is of no use for you, please pass it to a friend who develops software.

One of the primary design goals of the ARexxBox and especially the generated code was to come as close as possible to the ideas of the “User Interface Style Guide” by Commodore.

If you haven’t read this book yet, I’d recommend you do so before reading on and using the ARexxBox. Many of the potentially confusing things will be clearer to you.

In my opinion, we have to establish a standard for ARexx interfaces; I think it’s a very annoying thing for the user having to learn a new syntax and usage of ARexx for each new program she buys.

Of course, the Style Guide can’t give final solutions to all problems — many of the ideas mentioned in the Guide need to be extended a bit. Especially some standard command’s parameters leave some questions. I have tried to complete these things when converting them to ARexxBox, but there are certainly many more places than I recognized. If you do such an extension, please let me know, so we can share it amongst all ARB users.

ARexxBox is FreeWare, meaning you may copy and distribute it freely as long as you follow the conditions mentioned in the copyright chapter, but the complete ARexxBox is still copyrighted by me, the author. However, I grant you the right to use the generated code freely as long as you do not use it for military purposes as mentioned in the copyright chapter. You don’t have to pay any licenses for any part of the software.

All I’m asking for is that you put a remark into both the About window and the documentation for any software using ARB generated code stating that the ARexx interface was designed using the ARexxBox. Also, I’d like to get (email preferred) a list of the supported ARexx commands, but that’s not a must.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2 Addresses of the Authors

You can reach the author under one of the following addresses:

Mail:
   Michael Balzer
   Wildermuthstraße 18
   W-5828 Ennepetal        (58256 from july 1993 on!)
   GERMANY
InterNet Electronic Mail:
At work:
   balzer@heike.informatik.uni-dortmund.de

At home:
   bilbo@bagsend.aworld.de
or in the german Z-Net
   m.balzer@aworld.zer
or from Fido
   Michael Balzer of 2:241/5604.19

The Fido address hasn’t been tested up to now, if you don’t get a reply please try another way.

If you have questions concerning the Oberon-2 source, please contact:

Postadresse:
   hartmut Goebel
   Aufseßplatz 5
   W-8500 Nürnberg 40      (90459 from july 1993 on!)
   GERMANY
InterNet Electronic Mail:
At home:
   hartmut@oberon.nbg.sub.org
or in the german Z-Net (not very frequently)
   hartmut@asn.zer
or from Fido
   Harmut Goebel of 2:246/81.1

[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3 Introduction

You probably already know how important ARexx is to the Amiga. So I’ll concentrate on convincing you to use ARexxBox for your ARexx interfaces ;-).


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.1 Why ARexxBox?

ARexxBox (inspired by Jan van den Baard’s GadToolsBox) is a tool that eases the design, construction and implementation of an ARexx interface for a program. An interface generated by ARexxBox automatically conforms to the ARexx standards mentioned in Commodore’s “User Interface Style Guide”.

Here are the features:


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4 Requirements


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.1 Hardware

The hardware requirements are neglectible, ARB should run on any Amiga.

Okay, there’s one thing: As the ARB window is taller than 200 lines, you have to use something larger than that. Or you could set the system font to some 6 or 7 point font.

As programmers normally don’t work on a 640x200 screen, this shouldn’t cast any problems.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.2 Software

Both ARB and the generated code will only run on OS2.04 or higher.

The Box itself also makes use of the reqtools library by Nico Francois. This is only for the Box, the generated code does not use it!


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.3 C source

You will need an ANSI compatible C compiler which offers an option to include (link) functions from ‘amiga.lib’ by Commodore.

The ‘amiga.lib’ must be version 37.32 (12.11.91) or later. This version is available as part of the Native Developer’s Upgrade Kit for OS2.04.

You can do without ‘amiga.lib’. I reassembled the needed functions (GetRexxVar and SetRexxVar) and included them as separate source. Aztec spends very much time scanning ‘amiga.lib’, so if you link with this object you will get shorter turn-around times.

I, on the other hand, cannot guarantee that this code is completely compatible to those from ‘amiga.lib’, and of course you won’t make use of any future enhancements in the lib.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.4 Oberon-2 source

You will need AmigaOberon V3.0 or later.

The source is based upon a non standard class library and some other modules (see Oberon subdirectory).

The module RVI is an interface to some part of the amiga.lib, you have to link with this module if using amiga.lib functions:

OLink RxTest OBJ oberon:obj/amiga.lib

If you have got the object file “rexxvars.o” from one of the ARexx developer kits, you can use the $JOIN option to link it onto the object file of the RVI module. In this case, you don’t need to specify amiga.lib for linking. Doing the same with amiga.lib itself is not recommended, your files would become very big.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5 Installation

Basically you don’t have to install anything. Just copy all parts to a place where you (or your compiler) can find them. Some Oberon modules are not only for ARB but also of general use.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6 Usage

There’s nothing unusual in using ARexxBox. If you’ve ever used an amiga application, you should have no problems at all.

Before defining some complex ARexx interface, you should probably first read the chapter explaining the concept of the Box. To get a first impression, you could now load the file ‘arb/Misc.arb’. Click on GETATTR in the leftmost list.

The remaining two listviews should now fill with the parameters and result fields of the command GETATTR. Each element of any list can be changed using the gadgets below of the list.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.1 Input

To enter a command definition, do the following steps: Push key <N>, enter the name of the ARexx command and confirm with <RETURN>. ARexxBox will now convert all characters to upper case and those not allowed to underscores (‘_’) and then check if the name is unique. If there is already a command with that name, you can change the name of the new command and try again.

Then enter the arguments. For each argument, push <E> and enter the name (optionally with ReadArgs style type tags). This name will also be checked for collisions with existing arguments.

With results, it’s just the same, only the shortcut for a new result field is key <W>.

You can move args and results up and down, either just after entering them or later after selecting them via clicking on them, by pushing the gadgets labeled ‘up’ and ‘do’. You can remove any list element by selecting it and then clicking on ‘Remove’.

The types of the arguments and results must be given in ReadArgs() style (see AutoDocs), for example ARG1/K/N or LIST/M. Only the (optional and combinable) switches /N and /M are allowed for results.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.2 MsgPort Basename

The ‘MsgPort Basename’ is the default base name for all ARexx message ports opened by the application. If necessary, a proper number will be appended to the name to make it unique (e.g. “FOOWRITE.13”).

Any application should recognize the shell or workbench argument “PORTNAME” to change this base name. Such a user supplied base name will also be made unique via an appended number if necessary.

In addition, the MsgPort Basename will be used as the standard extension for ARexx script files for the application, so you should choose a short text for it. The PORTNAME tooltype has no effect on this.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.3 CommandShell

For C, ARB will generate additional code for a command shell if you turn this gadget on. You should normally leave it on, as the command shell code can also be used to execute external macro programs.

The switch makes no difference for Oberon, where the command shell code is always available.

The command shell is a kind of shell, which gives the user a direct interface to all ARexx commands of an application. The user can execute the ARexx commands from this shell as if it were a normal shell and the commands were DOS commands. The results of commands get printed in a readable form in the shell window.

For example, you could use the commandshell to quickly execute some macro without having to use ARexx directly. Or you can use this as a way to make some commands only available to the advanced user.

If you give a command shell a file as its input channel, it will execute the commands in the file line by line. So you can also use it to execute external macro programs.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.4 Merge in

Merge is like Open, only it does not clear the command list before loading the data file. Merge will only add commands which are not already defined in the current project.

So with merge, you can build your own ARexx command packages for different purposes and later combine them as you need them. I already entered all standard commands mentioned by the Style Guide, try to combine some of these packages into your test file.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.5 Print

This shall become a documentation aid. It currently only prints name, syntax and results for all commands. If you have a good suggestion on a better output format for this function, please tell me.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.6 Generate Source

Starts the source generator. You may select any part of an already existing source output in the file requester or enter a complete new base name. Any ARB extension (‘.c’, ‘.h’ or ‘_rxif.c’ or for Oberon ‘.mod’) will be cut off. Some safety checks will be done (e.g. if you are going to destroy another file accidentally) and then the source will be generated.

The new source files first go into ‘T:’, to prevent possible damages caused by crashes or other bad things. The new files will be copied to the actual destination directory as soon as they have been completed in ‘T:’.

The new files in ‘T:’ won’t be deleted if some error happens while copying them to their real location. So if some bad things happen, you still have a chance to save them yourself.

When generating the source, the Box will set the internal status of all commands to ‘old’. A new command has status ‘new’ and if you edit a command, the Box sets the status to ‘changed’. The source generator relies on this status flag to tell which commands have been altered since the last source generation. If a command has been altered, the generator will put a remark (“ATT: Interface changed!”) into the source right before the interface function correlating to that command.

You should look for this comment and check the consistency of the interface and the variable naming of the RXD structure against the real (perhaps on some older version basing) code before compiling again. Some cases the compiler won’t find...

An important thing to have this remarks working is to save an ARB project after generating the source to it. If you do not save it, the changes of the status flags won’t be saved as well. That’s not tragic, but the Box will not know about the changes next time.

There are currently two source generators available, one for C (the original thing) and one for Oberon (by hartmut Goebel). Please ask hartmut if you have questions concerning the Oberon part.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

6.7 Clipboard

Cut, Copy and Erase work on either the currently selected command or on a range of commands.

To mark a range for these operations, choose “Mark Range”, click on the first and then on the last command of the wanted range.

Selecting a single command clears the range selection.

Paste, like Merge, will only include commands not already there.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

7 Concept

Besides conforming to the Style Guide, another primary design goal of ARexxBox was to ease the usage of ARexx to a programmer as much as possible.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

7.1 Initializing

The function SetupARexxHost() will open the ARexx port and return a pointer to an object of the type struct RexxHost. This pointer is a kind of file handle for the ARexx port, all other ARexx functions generated by the Box need this pointer.

In Oberon-2 SetupARexxHost() also returns a pointer, which serves as the ‘receiver’ of the methods.

So all operations relate to a specific port (an application can have any number of ARexx ports, e.g. a text editor could open one port for each open file).


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

7.2 Commands from ARexx

To handle its ARexx port, all the application has to do is listen to the port (signal) and call the function ARexxDispatch(), which will fetch and handle all incoming messages until the port is empty and then return.

Each command has its corresponding interface function (the interface between ARexx and your code), the address of this interface function is in the command list entry to the command. Normally such an interface function just checks the parameters and then calls the right core functions of your application. All you have to do is implementing these interface functions — and the Box will help you by generating the skeleton code for each new command.

The actual (user supplied) parameters for a command are passed to the interface function via a specially created data structure. The interface function in turn returns its results by storing them in the same data structure before returning. The ARB routines take care to pass the results back to ARexx according to their types and conforming to the Style Guide.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

7.3 Expanding commands

To support both the ALIAS standard command and other things like macros, there is a callback function which will be called by the parser before discarding an unknown command.

The parser analyzes incoming command lines and determines which interface function to call. If the command line does not match any command of the list, the parser will call ExpandRXCommand(), which could then do an ALIAS expansion and return the substituted command to the parser.

The parser will then try once again to recognize the command. If this second try fails again, the original command will be sent to the ARexx server process. So if there is an external script program of this name, it will be executed as if it were an internal part of your application, external commands are totally transparent to the user. The result of an external command will be sent back to the original caller.

Demonstration of this feature: Change to directory ‘test’ and start ‘test’. Close the CommandShell by typing EOF (<C-\>) and then enter the following command in another shell:

rx "options results; address 'arbtest'; test 'FooBar'; say result"

As the test program does not have an internal command called “test”, the external script ‘test.arbtest’ will be executed, which in turn will output a message into the output window of the test program and then return the string “Testtext!” to the caller (yeah, I know, very imaginative).

If no external command of the given name exists, the command will finally be classified as “unknown” and the parser will return an error to the caller.

Once again the complete process for a command:

  1. Command in internal command list?
  2. If not: ExpandRXCommand() -> new Command known?
  3. If not: Is it an external script?
  4. If not: Error - not implemented

[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

7.4 Commands to ARexx

Of course the application may also send commands to ARexx, there are some special support functions for this direction available (see SendRexxCommand).

As such commands generally (being just normal Exec messages) run asynchronously, the ARexxBox has a special mechanism to react on the return of such a call. So you can start an ARexx command and then later get the result from it. Of course you have to make sure you can identify which result belongs to which command (see chapter on how to use the code).

To prevent late replies to break, the Box routines will count all sent commands and reject to close the port until all replies have been received (see Closedown).


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

7.5 Closedown

SetupARexxHost’s counterpart is obviously CloseDownARexxHost. This one closes the port and releases all allocated ressources.

The final closedown may be delayed automatically, if there are some commands which were sent to ARexx but have not returned yet. The Box will then wait for all these commands to be finished before closing the port. Any new commands coming up during this phase will be returned immediately with an error “Host closing down”.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

8 Files

The source generated by ARB should be compilable without any changes. All needed interface functions (the only part you have to work on) should at least be there as empty template code.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

8.1 C

The C source consists of five files:


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

8.2 Oberon

The Oberon source consists of four files:


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

8.3 ARB special comments

In the interface module, the Box will generate some comments of the form /* $ARB: ... */ (or on Oberon (* !ARB: ... *), which must not be changed in any way.

Somewhere at the top of the interface module there will be a comment telling to which project file this source module belongs. The Box will check this ID and reject to extend an existing code which has been generated from another ARB project.

Each interface function is enclosed in two comments (‘B’egin and ‘E’nd with ID of function). All source code between these two comments will be considered as belonging to this function and will always be preserved (or moved to the storage file) completely. So if you need some variables or support functions for an interface function, be sure to define them between the proper comment lines.

If you changed the definition of a command, the Box will generate a warning comment right ahead of the corresponding interface function. This comment of the form “ATT: Interface changed!” may be removed, but you really should first check if the code needs to be changed according to the new arguments or results.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

9 Interface Functions


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

9.1 Basics

An interface function consists of three phases,

which will be called by the ARexxBox routines in this order.

The first phase serves for allocating and initializing the memory for the transfer data structure that will transfer the arguments and result values between the basic functions and the interface function.

You can also use this phase for other initializations, e.g. allocating local buffer memory or the like.

The second phase should do the actual work and use the parameters from the previously (phase 1) allocated transfer structure. Any results should be stored into this structure as well before returning.

There are two special elements in every transfer structure, rc and rc2. These two relate to the normal return codes, any ARexx command may produce. In addition, the ARB offers an extended error code system (see chapter on Errors).

After execution of phase 2, the Box will extract all results and send them back to the ARexx server process. Then phase 3 will be called for freeing all locally allocated ressources.

You will find some working examples on the form and function of interface functions in the directory ‘rxif’. Especially the — completely working — HELP function should serve well as a complex example.

Anyway, here is the concrete structure of an interface function:

void rx_help( struct RexxHost *host, struct rxd_help **rxd,
              long action, struct RexxMsg *rexxmsg )
{
    struct rxd_help *rd = *rxd;   /* for simplification and local
                                     extensions */

    struct rxs_command *rxc;      /* local variables */
    int cnt = 1;

    switch( action )
    {
        case RXIF_INIT:
            /* Phase 1! */
            /* allocate the transfer structure */
            *rxd = calloc( sizeof *rd, 1 );
            /* no defaults to set, so just return */
            break;
            
        case RXIF_ACTION:
            /* Phase 2! */
            /* do it! */
            
            if( rd->arg.prompt )
            {
                rd->rc = -10;
                rd->rc2 = (long) "Prompt option not yet implemented";
                return;
            }
            
            and so on, making also some allocations:
                rd->res.commanddesc = malloc( ... )
            and
                rd->res.commandlist = [calloc];
            which have to be freed in phase 3...
            
            break;
        
        case RXIF_FREE:
            /* Phase 3! */
            /* free any allocated ressources */
            
            if( rd->res.commanddesc )
                free( rd->res.commanddesc );
            if( rd->res.commandlist )
                free( rd->res.commandlist );
            
            /* free the transfer object */
            free( rd );
            break;
    }
    
    /* back to the dispatcher */
    return;
}

[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

9.2 Local Memory

If you need local memory in an interface function, you must not use static or global variables in any case! Always remember: Your interface code has to be reentrant, any interface function may be called many times at once — not only if more than one port is open! Also local static variables do not fit into object oriented design (and would cause big troubles in Oberon for example).

There’s a simple trick for local memory: Just extend the transfer structure, add elements for your local variables locally at the end. Example:

void rx_rx( struct RexxHost *host, struct rxd_rx **rxd,
            long action, struct RexxMsg *rexxmsg )
{
    struct {
        /* first the original structure */
        struct rxd_rx rd;
        /* followed by our local extension(s) */
        long tempval;
        char *tempbuffer;
        ...
    } *rd = (void *) *rxd;
...

Or in Oberon:

PROCEDURE Rx * (host: rxh.RexxHost; VAR rxd: rxh.RXDPtr; action: INTEGER);
VAR
  rd: POINTER TO RECORD (rxdRx) (* Extension of the original structure *)
    tempval: LONGINT;
    tempbuffer: BT.DynString;
    ...
  END;
...

As you can see, we made a local extension of the rxd_rx structure, giving us ‘local’ variables (tempval and tempbuffer). As the transfer structure including these extensions will be allocated during the first phase and freed in the last phase, these variables can be used like local memory without any conflict.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

9.3 Examples

There are some example commands (their interface functions) in the directory named ‘rxif’. Some of them are ready-to-use, e.g. the HELP command only needs an application specific graphical user interface.

If you have written a commonly usable (i.e. application independant) command and would like to give it to the whole community of ARexxBox users, please send it to me (command definition, functionality and source), I will include it in the next release.

I would like to see a library of standard commands arise, which can easily be included into any project. Such a library of ARexx commands would make ARexx interface development even easier.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

10 Arguments & Results


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

10.1 Arguments

The ARexxBox concept has been developed from the ideas and suggestions of the Style Guide.

One of the essential basics of this concept is to have the arguments of ARexx commands looking and feeling just like normal shell command arguments. So the Box uses the DOS function ReadArgs() to parse the parameters of a concrete command.

First of all, you should now read the chapter on ReadArgs.

Okay. Now to the Box’s specialities:

If a command has at least one result field, the Box will automatically generate the two (invisible) arguments VAR and STEM.

These give the user of the final application the option to choose the result method. There are two methods, the first (RESULT/VAR) returns all assigned result fields concatenated and separated by spaces in one variable, the second (STEM) uses an ARexx stem variable to separate the result fields.

If neither VAR nor STEM were specified by the user, method one (concatenated) will be used to return all results in the standard ARexx variable RESULT.

If the user wants to have structured results, she should choose the STEM method.

VAR and STEM are not mutually exclusive, the user may use both methods at the same time. There will be no RESULT variable assignment if at least one of these options is in use.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

10.2 Results

In order to offer a consistant interface in both directions, the ARexxBox code implements exactly the same syntax and method which is used for arguments also for the results. There’s one restriction on the type tags allowed for results: Only the optional type switches </N> and </M> are supported up to now. Switches like </K> do not make any sense for results, and instead of boolean results (</S> or </T>) you better use integer fields, which are more flexible, as an integer only appears in the output if set.

Here are the types for results:

As you can see, the results (which your interface function will produce!) may be of the same types as the arguments. Of course, all result fields are optional as well, if you don’t assign any value to the foobar result above, it will not show up in the result of the command.

An example: Start the Box, open the file ‘arb/Other.arb’ and select the HELP command. As you can see, the HELP command has two result fields, one beeing a simple string (COMMANDDESC) and one beeing an array of strings (COMMANDLIST).

This means, the ARexxBox will generate the following result fields in the transfer structure for this command, struct rxd_help:

In C:

    char *commanddesc;
    char **commandlist;

In Oberon (the types have been resolved for this example):

    commanddesc: BasicTypes.DynString;
    commandlist: POINTER TO ARRAY OF BasicTypes.DynString;

Your HELP command may set any of these two fields by assigning values to them, e.g.

    static char *myarray[4] = { "foo", "bar", "dubidu", NULL };
    rxd->res.commanddesc = "Blafasel";
    rxd->res.commandlist = myarray;

In Oberon you also have to take care of the string length, but the lists also don’t need a closing NIL:

    rxd.res.commanddesc := MoreStrings.CopyString("Blafasel");
    NEW(rxd.res.commandlist,3); (* three entries *)
    rxd.res.commandlist[1] := MoreStrings.CopyString("foo");
    rxd.res.commandlist[2] := MoreStrings.CopyString("bar");
    rxd.res.commandlist[3] := MoreStrings.CopyString("dubidu");

(Remark: The normal HELP command will set only one of the two results (depending on the parameters), but it could assign both if necessary.)

The ARB does all the conversions and assignments which are necessary to have the result method beeing Style Guide conform: Integers will be converted to strings, array entries will be counted and their number will be put in front of them.

You can check it out easily: Start the test program (‘test/test’) and enter help in the command shell. Without any parameter, the command will produce the list of commands understood by the test program’s ARexx interface, doing so by only assigning the field rxd->res.commandlist.

The output contains the number of commands (list entries that is) followed by the commands (entries). This is the result method for single, unstructured variables, what you see is exactly what would have been assigned to the RESULT variable if the command would have been triggered from ARexx instead of the command shell. This output may be redirected into any variable using the keyword VAR.

Now enter help stem kl.. Examine the output, this is exactly what would have been used as an assignment list for ARexx. For this structured result method, arrays get a new first element called resultname.COUNT followed by the entries of the array numbered from 0 upto COUNT-1.

The example above would produce the following result:

Using VAR method:

    "BlaFasel 3 foo bar dubidu"

Using STEM method with root name hr (recommended method because of the multiple, structured result values):

    hr.COMMANDDESC = "BlaFasel"
    hr.COMMANDLIST.COUNT = 3
    hr.COMMANDLIST.0 = "foo"
    hr.COMMANDLIST.1 = "bar"
    hr.COMMANDLIST.2 = "dubidu"

An ARexx program may traverse these lists using a simple loop:

help stem a.
say 'There are' a.commandlist.count 'commands available, that are:'
do i=0 to a.commandlist.count-1
    say a.commandlist.i
    end i

Do you still have that test program running? Good. Enter help stem single. help. The HELP command will now only assign a value to the result field COMMANDDESC (Feld rxd->res.commanddesc). As you can see, the output reflects also clearly, which result field has been used for the result. This only applies to the STEM method.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

11 Error Codes

If a command cannot execute normally, it should return an error code reflecting this condition so the caller can react on the problem.

For this purpose ARexx normally only offers the RC variable, which may be set to an integer error code (normal range 0..20).

The ARexxBox offers a slightly extended method with an automatically generated variable called RC2. This variable can hold error codes as well as strings (descriptions), which may be read by the calling ARexx program after command execution.

So we have two error variables, rc and rc2, in every transfer structure. The sign of rc serves as the type tag for rc2, if rc is positive, rc2 is an integer value, if rc is negative, rc2 is a string pointer.

Here’s an example for an additional integer error code (you should use DOS error codes where possible):

    rd->rc = 10;
    rd->rc2 = ERROR_NO_FREE_STORE;

And here’s one for an additional error description:

    rd->rc = -10;
    rd->rc2 = (long) "Prompt option not yet implemented";

The last one again for Oberon:

    rd.rc = -10;
    rd.rc2 = SYSTEM.ADR("Prompt option not yet implemented");

An integer value will of course be converted to a string, strings will be passed to ARexx without change. A negative rc will be converted to positive.

This extended error return method is not a Style Guide suggestion, but I think it’s a good and usable extension, as you can give the user detailed error strings in addition to the simple RC value.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12 How to use the generated Code


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.1 Design questions

It’s a good idea to build applications in an object oriented manner beginning with the core functions inside and building layers of interface functions around the core. On an ideal application core one should be able to build interface functions for any user interface - be it graphical or textual or...

With such a design, you don’t have much problems implementing the interface layer for the graphical user interface. And the layer for ARexx consists of the interface functions pregenerated by the ARexxBox and later completed by you. Another interface layer could for example be made for terminals at the serial port.

A core of basic application functions greatly simplifies the implementation of the ARexx layer.

A simple example: Imagine an application opening files. This opening of a file with a given path and name could be a basic core function, errors could be returned through defined return values to the caller (that is an interface function).

The GUI layer would then contain a function which gets called by the window dispatcher if the user chooses submenu “Open” from the projects menu. This function would then open a file requester, read the name and then call the core function to actually load the file. Any error codes would be given to the user via suitable requesters.

The corresponding function of the ARexx interface layer needn’t do as much, as it normally will receive the name of the file to open as a parameter. All it has to do is do a parameter check and then call the same core function. Any problems would be returned to ARexx through the error result fields.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2 Example

This example is not an example for the ideal layer design mentioned in the chapter before, it’s merely an example on how to use the basic functions generated by the ARexxBox.

You should now load the file ‘test/test.c’ into your text editor and examine the implementation of the following steps.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.1 Initializing

There’s only one library you have to open for the ARexxBox generated code, the rexxsyslib.library. Of course you should offer an option to the user for changing the base name of the ARexx port.

If you intend to make use of the result hook mechanism (remember: to handle asynchronous results from commands you sent off to ARexx), you should assign the address of your result hook function to the global variable ARexxResultHook. For Oberon you would redefine the abstract method ‘HandleResult’ in the proper module of your project.

Now, to open the ARexx port and do all the necessary internal inits, just call SetupARexxHost().


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.2 CommandShell

The command shell needs an input and an output channel. The example just opens a normal console window, but you could also use files for that purpose (e.g. to execute scripts).

The command shell runs synchronously, the call will not return until the input channel is empty (EOF or Ctrl-\ from the console).

Of course the caller has to close the I/O channels.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.3 SendRexxCommand

As you can see, sending commands to ARexx is very simple.

If you want to differ between the results your result hook will get, you have to take care of the result recognization yourself. Remember: The results will come in an unpredictable order, depending on what the commands did and what else was running.

One possible method is to store the addresses of all ARexx messages you send off and later compare them to the addresses of the result messages, as ARexx will (currently) use the same message object for results. But that may change anytime, so I’d recommend this method: Use one of the free ARG fields of an ARexxMessage to store any kind of message ID there. For this method you will have to do the two steps of SendRexxCommand() yourself by first calling CreateRexxCommand(), then assigning the ID and then calling CommandToRexx().


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.4 ARexxDispatch

Now you do what any Amiga application does - wait for signals. If the ARexx port triggers a signal, you simply call ARexxDispatch(). The ARexx dispatcher will process all messages on the port and then return.

Of course, the same structure (signal -> dispatcher) can be used for windows (the whole GUI layer).


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

12.2.5 CloseDown

The example program does an indirect closedown, the CloseDownARexxHost() call is in the function closedown() which was hooked onto the exit procedure before. The return of the CloseDown routine may be delayed if there are any outstanding replies. Take care: Also the routine pointed to by ARexxResultHook may be called in that situation!


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

13 Hints concerning the Oberon-2 source

These are some remarks to the concept, implementation and some design decisions of the Oberon-2 source by hartmut Goebel.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

13.1 Concept

One design goal of this implementation was to give the programmer full type safety while retaining the comfortable aspects of Oberon (e.g. the garbage collector). This was a challenge to me, as the parameters of the result structure depend on the result template and cannot be checked at compile time(2).

Another goal was to build upon the PortHandle class library, that was under development right then — some ideas from ARB have been used there as well.

As a conclusion from this, the source has been designed in an object oriented manner. This was no problem, as the original C design is also object oriented. Merely the interface functions have not been designed to be methods, as they couldn’t be called in a generic way otherwise.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

13.2 Results

While the parameters will be parsed by Dos.ReadArgs() which will put their values into the special transfer structure (see also ’ReadArgs’), this job has to be done by ARBRexxHost for the results. This offers the chance to at least have the full Oberon type safety and comfort with the results.

The following type equivalence applies to the results (type descriptors have been resolved):

As you can see, /M results are dynamic arrays. You only need to allocate them with the needed number of elements and enter the data, for example:

NEW(rx.res.foobar,10);

for 10 list entries.

You don’t need the final NIL (like with C) with Oberon. This is also the reason for /M/N results being directly an ARRAY OF LONGINT instead of an ARRAY OF POINTER TO LONGINT. This is a little inconsistant for the interface, but much more comfortable.

Parameters and simple numerical results have been declared as POINTER TO ARRAY 1 OF CHAR, as Oberon does not support pointers to unstructured types (although AmigaOberon does).


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

13.3 Documentation

As the design and language is completely different from C, the C documentation is not very good for the Oberon side. This applies especially to the procedures defined by the PortHandle class library and its extension ARBRexxHost.

I therefore recommend using the documentation to this library. You should find all needed information there. If not, please tell me what misses and I will complete it.

hartmut Goebel


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

14 ReadArgs

ReadArgs() uses ascii templates to know the number and types of the arguments. The destination memory is just an array of longwords, which have to be interpreted by the program corresponding to their types.

Example: A template “DATEI,ARG1,FORCE” means there are three possible arguments. So the destination array must be able to hold at least three longwords.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

14.1 Template syntax

ReadArgs() allows five basic data types identified by special appended switches in the template string:

It’s essential to remember, that every argument (besides those with /A for ‘Always required’) is optional and doesn’t need to have any assignment.

Example: FILE/A,LINES/N,STDIN/S means, three arguments are possible, but only the first one must be specified by the user. The first one is a string, the second an integer and the third is a boolean.

It is possible to force the user to put the keyword before an argument by adding the /K switch, this may be necessary for complex templates. Also you can define aliases for a keyword (e.g. abbreviations).

Example: FILES/M/A,AS=TO/K/A is the template for the AmigaDOS join command. It forces the user to put either ‘AS’ or ‘TO’ right before the destination file. Valid argument lines for this template would be:

The last example demonstrates that ReadArgs() doesn’t need a fixed order of the parameters if the user specifies the keywords. And ‘KEYWORD DATA’ is equivalent to ‘KEYWORD=DATA’.

Forcing the user to use the keywords is a must be in many situations with multiple arguments, as ReadArgs() would otherwise have problems to differ between those arguments for the array and those for the other arguments.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

14.2 Results

Boolean arguments can be specified or not in an actual argument line, so their state is represented by a plain longword.

All other types are completely optional, so they are represented not by objects but by pointers to objects. If a pointer is NULL, no value was specified for the related argument. Strings are pointers to characters, integers are pointers to longwords. Lists are NULL–terminated arrays of pointers to either strings or longwords.

The following type equivalence results for C:

The module ARBRexxHost defines these types for Oberon.

Another example: The template FILES/M/A,AS=TO/K/A,FORCE/S,MAX/N,SOUND/T,LINES/N/M would have the following data structure for the argument values:

struct readargs_result
{
    char **files;
    char *to;
    long force;
    long *max;
    long sound;
    long **lines;
} rda_result;

(Remark: This template is not correct, it’s merely an example for the type equivalence. Actually a template may contain only one </M> switch.)

The fields of the structure may be assigned default values before calling ReadArgs(), the system call will only alter those elements whose arguments have been specified by the user. Boolean arguments are different: /S arguments will always be set according to their keyword being specified (if not specified, the value will be zero), but /T arguments will toggle the previously set default value — in theory, I haven’t tested this behaviour yet.

So for strings and integers you can see from the primary pointer in the structure above, if the parameter has been specified at all. Otherwise the pointer is NULL.

Arrays may be of any size, so their end has to be marked by a NULL entry.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

14.3 More Features

There’s another switch, </F>, used to assign an argument the whole rest of the command line from that point, no matter what keywords or special characters may be in it. You normally don’t need this one and should take care if you use it.

Parameters which are not set in between quotation marks by the user will first be checked against the possible keywords. So an input of “foo bar all qwe” to a template “Dir/M,All/S” will set the switch ALL and return the array “foo”, “bar”, “qwe” in DIR. If the user had specified “all” in quotation marks, it would have been taken into the array instead of being considered as being the ALL switch.

As mentioned above, you should not have more than one array (</M>) per template to avoid problems.

If there are unassigned /A arguments left after parsing, ReadArgs() will first try to fill them with the last elements of any /M type argument. An example for this behaviour is the copy command: The template “From/A/M,To/A” with an input of “copy file1 file2 file3 destination” will assign the last word to the TO argument — just like you’d expect it to do.

On ReadArgs please also see ‘AutoDocs:dos.doc’.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

15 Library


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

15.1 ARexxBox/ARexxDispatch

ARexxBox/ARexxDispatch                                 ARexxBox/ARexxDispatch

   NAME
        ARexxDispatch -- get ARexx command from MsgPort and execute it

   SYNOPSIS
        ARexxDispatch( rexxhost );

        void ARexxDispatch( struct RexxHost * );

   FUNCTION
        ARexxDispatch fetches and executes all queued commands from
        the given RexxHost's message port.
        
        If a reply for some previously (with SendRexxCommand()) sent
        command comes in, the counter variable for still outstanding
        replies will be decreased by one and the RexxMsg and it's
        associated memory will be freed by FreeRexxCommand().
        
        In the main program, you should just check for the signal
        of the host's message port and call ARexxDispatch()
        without actually getting the message. All work will be
        done by the dispatcher.

   INPUTS
        rexxhost - pointer to an active RexxHost structure with
                   a valid MsgPort

   RESULTS

   SEE ALSO
        SendRexxCommand(), SetupARexxHost(), DoShellCommand()


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

15.2 ARexxBox/CloseDownARexxHost

ARexxBox/CloseDownARexxHost                       ARexxBox/CloseDownARexxHost

   NAME
        CloseDownARexxHost -- close & free ARexx host

   SYNOPSIS
        CloseDownARexxHost( rexxhost );

        void CloseDownARexxHost( struct RexxHost * );

   FUNCTION
        CloseDownARexxHost() waits until replies for all pending
        ARexx commands have been received and then closes the
        ARexx port and frees all memory associated with that
        RexxHost structure.
        
        All messages sent to a closing host will be replied
        immediately with an error "Host closing down".

   INPUTS
        rexxhost - the RexxHost to close down

   RESULTS

   SEE ALSO
        SetupARexxHost(), SendRexxCommand()


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

15.3 ARexxBox/CommandShell

ARexxBox/CommandShell                                   ARexxBox/CommandShell

   NAME
        CommandShell -- process Commands from a file

   SYNOPSIS
        CommandShell( rexxhost, fhin, fhout, prompt );

        void CommandShell( struct RexxHost *, BPTR, BPTR, char * );

   FUNCTION
        CommandShell() sets the Flag ARB_HF_CMDSHELL in the
        RexxHost's flag field and then processes input from fhin
        until EOF or the CmdShell flag in the RexxHost being cleared
        (e.g. by the standard Rexx command "CMDSHELL CLOSE").
        
        The input is read line-wise, with newline as EOL. Each
        line will be parsed and executed just like a built-in custom
        ARexx command, exactly like it was called via an ARexx host
        messageport.
        
        The parsing and execution of each line is done by the
        function DoShellCommand().
        
        If fhout is not NULL, the output of the commands will be
        printed to fhout. The output of the commands will NOT be
        assigned to any variables, as there is no underlying ARexx
        script program that could hold these variables. Instead,
        the output will be formatted to be human-readable.
        
        The prompt string (if not NULL) will be printed to fhout
        as an input request before reading an input line.
        
        New (ARB 0.99d): The rexxhost parameter has to point to a
        valid RexxHost structure. This is for identifying which
        command shell belongs to which window/instance of the main
        process.
        
        New( ARB 0.99e):  To support the "RX" command sending
        asynchronous messages to ARexx, this function now catches
        the replies of those messages and frees them using
        FreeRexxCommand().  Messages sent _to_ this host will be
        replied immediately with an error "CommandShell Port".

   INPUTS
        rexxhost - an initialized RexxHost structure
        fhin - the input FileHandle (see dos.library/Open())
        fhout - the output FileHandle (or NULL)
        prompt - the prompt string (or NULL)

   RESULTS

   SEE ALSO
        DoShellCommand(), ARexxDispatch(), dos.library/Open()


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

15.4 ARexxBox/CommandToRexx

ARexxBox/CommandToRexx                                 ARexxBox/CommandToRexx

   NAME
        CommandToRexx -- send a prepared RexxMsg to the ARexx server

   SYNOPSIS
        msg = CommandToRexx( rexxhost, rexxmessage );

        struct RexxMsg *CommandToRexx( struct RexxHost *, struct RexxMsg * );

   FUNCTION
        CommandToRexx just sends the given RexxMsg to the ARexx
        server process without changing any fields of the Msg.
        It will also increment the counter for outstanding replies
        in the RexxHost structure.
        
        You can use this function together with CreateRexxCommand()
        to easily create customizable command messages for Rexx.

   INPUTS
        rexxhost - an initialized RexxHost structure
        rexxmessage - an initialized ARexx message

   RESULTS
        msg - the same as rexxmessage, just for easy further processing

   SEE ALSO
        CreateRexxCommand(), SendRexxCommand()


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

15.5 ARexxBox/CreateRexxCommand

ARexxBox/CreateRexxCommand                         ARexxBox/CreateRexxCommand

   NAME
        CreateRexxCommand -- allocate & initialize rexxmsg for a command

   SYNOPSIS
        rexxmsg = CreateRexxCommand( rexxhost, command, fh );

        struct RexxMsg *CreateRexxCommand( struct RexxHost *, char *, BPTR );

   FUNCTION
        This function will create a RexxMsg structure for the given
        RexxHost, create an Argstring from the command string and
        use that string to initialize the message as a RXCOMM type
        with RXFF_RESULT requested.
        
        The file handle will be used for both input and output.
        
        You can use this function to create a standard ARexx command
        with the additional possibility to set some extra parameters
        before sending the command to ARexx using CommandToRexx().

   INPUTS
        rexxhost - an initialized RexxHost structure
        command - the command string
        fh - the input/output FileHandle (see dos.library/Open())

   RESULTS
        rexxmsg - a pointer to the new RexxMsg structure

   SEE ALSO
        CommandToRexx(), SendRexxCommand(), dos.library/Open()


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

15.6 ARexxBox/DoShellCommand

ARexxBox/DoShellCommand                               ARexxBox/DoShellCommand

   NAME
        DoShellCommand -- parse & execute a command line

   SYNOPSIS
        DoShellCommand( rexxhost, commandline, fhout );

        void DoShellCommand( struct RexxHost *, char *, BPTR );

   FUNCTION
        DoShellCommand parses the given string assuming it contains
        an ARexx-style command line.
        
        New (ARB 0.99e):  If normal parsing fails, the external
        function ExpandRXCommand() will be called to expand any
        macros.  If the expansion fails or the expanded command
        can't be recognized either, an error will be returned.
        
        If no errors occur during parsing, it tries to execute the
        command with the given arguments. The results of the command's
        execution will be printed in a human-readable format to fhout
        if fhout is not NULL.
        
        If errors occur, DoShellCommand prints a string describing
        the error to fhout (if not NULL).
        
        New (ARB 0.99d): The rexxhost parameter has to point to a
        valid RexxHost structure. This is for identifying which
        command shell belongs to which window/instance of the main
        process.

   INPUTS
        rexxhost - an initialized RexxHost structure
        commandline - the string to be parsed & executed
        fhout - the output FileHandle (or NULL)

   RESULTS
        none

   SEE ALSO
        CommandShell(), ExpandRXCommand(), <dos/dos.h>


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

15.7 ARexxBox/ExpandRXCommand

ARexxBox/ExpandRXCommand                             ARexxBox/ExpandRXCommand

   NAME
        ExpandRXCommand -- expand macros and/or aliases (V0.99e)

   SYNOPSIS
        newcommand = ExpandRXCommand( rexxhost, oldcommand )

        char *ExpandRXCommand( struct RexxHost *, char * );

   FUNCTION
        This is an 'external' function you should provide if you
        want to have command aliases or the like. The minimal
        version of this function is just a return(NULL) as generated
        in the rxif module.
        
        ExpandRXCommand() will be called by the parser if it doesn't
        know how to interpret a command string. Expansion could now
        for example be a look up in the host's macro table.
        
        Any strings returned by this function have to be allocated
        explicitly using the standard C memory functions.  The
        calling parser will free() them.

   INPUTS
        rexxhost - the RexxHost we are working on
        oldcommand - the commandline the parser doesn't know

   RESULTS
        newcommand - an explicitly allocated memory area con-
                     taining the expanded command (or NULL)

   SEE ALSO
        DoShellCommand(), ARexxDispatch()


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

15.8 ARexxBox/FindRXCommand

ARexxBox/FindRXCommand                                 ARexxBox/FindRXCommand

   NAME
        FindRXCommand -- search the ARexxBox command table (V0.99e)

   SYNOPSIS
        rxscmd = FindRXCommand( command )

        struct rxs_command *FindRXCommand( char * );

   FUNCTION
        This function returns a pointer to the given command's entry
        in the ARexxBox-generated command table.  It exists to
        support those functions working on/with commands, like HELP
        or ENABLE/DISABLE.
        
        This function does no macro expansion.  The comparisons are
        case independant so you don't have to convert your input to
        upper case beforehand.  As this is exactly the routine used
        by the parser to find a command, it will handle
        abbreviations.

   INPUTS
        command - the command name to search for

   RESULTS
        rxscmd - the rxs_command structure of that command
                 (or NULL if command not found)

   SEE ALSO


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

15.9 ARexxBox/FreeRexxCommand

ARexxBox/FreeRexxCommand                             ARexxBox/FreeRexxCommand

   NAME
        FreeRexxCommand -- free the associated memory of a RexxMsg

   SYNOPSIS
        FreeRexxCommand( rexxmessage );

        void FreeRexxCommand( struct RexxMsg * );

   FUNCTION
        This is basically a PD ARexx routine provided by William S. Hawes.
        
        It frees all memory associated with a particular (previuosly sent)
        ARexx message structure. It will also close any stdin/stdout
        channels associated to that Rexx message.
        
        You normally shouldn't have to bother with this one because the
        dispatcher will call it for you.

   INPUTS
        rexxmsg - the rexx message to free

   RESULTS

   SEE ALSO
        SendRexxCommand()


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

15.10 ARexxBox/ReplyRexxCommand

ARexxBox/ReplyRexxCommand                           ARexxBox/ReplyRexxCommand

   NAME
        ReplyRexxCommand -- reply a rexx message from rexxmast

   SYNOPSIS
        ReplyRexxCommand( rexxmsg, primary, secondary, result );

        void ReplyRexxCommand( struct RexxMsg *, long, long, char * );

   FUNCTION
        This is a PD ARexx routine provided by William S. Hawes.
        
        It replies a given rexx message to the rexx master process,
        filling in a primary and a secondary return code plus
        optionally a supplied result string.
        
        The result string will only be converted to an ARexx string,
        if the primary return code equals 0, and will then destroy the
        contents of the secondary return code. So you provide either
        primary and secondary return codes or a result string.
        
        You normally shouldn't have to call this function!
        It is only mentioned here, because it is not part of the
        ARexxBox routines, but part of the original ARexx distribution
        by William S. Hawes.
        
        New (ARB V0.99d): Now creates an ARexx variable "RC2" for the
        secondary return code. If primary is positive, secondary is
        interpreted as a long, if primary is negative, secondary is
        interpreted as a char *. RC will become positive in any case.
        
        RC2 will only be assigned if the ARexx RESULT flag is set.

   INPUTS
        rexxmsg - the message structure to reply
        primary - the primary return code (rc)      ( >0      <0   )
        secondary - the secondary return code (rc2) (long or char *)
        result - the result string

   RESULTS

   SEE ALSO
        SendRexxCommand(), FreeRexxCommand()


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

15.11 ARexxBox/SendRexxCommand

ARexxBox/SendRexxCommand                             ARexxBox/SendRexxCommand

   NAME
        SendRexxCommand -- invoke rexx command script

   SYNOPSIS
        rexxmsg = SendRexxCommand( rexxhost, command, filehandle )

        struct RexxMsg *SendRexxCommand( struct RexxHost *, char *, BPTR );

   FUNCTION
        This is basically a PD ARexx routine provided by William
        S. Hawes.
        
        This function sends the given command string to the ARexx
        master process for execution as an ARexx command. The
        command string contains the file name of the ARexx script
        to be started. If the filehandle is not NULL, it will be
        used as stdin and stdout for the Rexx script. If it is
        NULL, the Rexx program will use stdin/stdout of the
        calling process.
        
        If necessary, the default extension (defined in the
        generated header file under the name REXX_EXTENSION) will
        be added to the file name.
        
        Messages sent using this function will be replied to by
        the ARexx master process as soon as the execution of the
        command script stops. The application MUST NOT close
        it's messageport before all replies have been received!
        To simplify things, ARexxBox does this book-keeping for you.
        CloseDownARexxHost() will wait for all missing replies to
        arrive before closing down the messageport.
        
        The dispatcher will automagically detect any replies,
        count them and do a FreeRexxCommand() for each reply, so
        you don't have to bother with this either.
        
        Internally, this function is implemented using the two
        more atomic functions CreateRexxCommand() and
        CommandToRexx().

   INPUTS
        rexxhost - the RexxHost to be used to send the command
        command - the file name of the ARexx script
        filehandle - Filehandle for stdin/stdout or NULL

   RESULTS
        rexxmsg - the sent rexx message structure (for comparisons)

   SEE ALSO
        FreeRexxCommand(), CloseDownARexxHost(), ARexxDispatch(),
        CreateRexxCommand(), CommandToRexx()


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

15.12 ARexxBox/SetupARexxHost

ARexxBox/SetupARexxHost                               ARexxBox/SetupARexxHost

   NAME
        SetupARexxHost -- initialize and open an ARexx host

   SYNOPSIS
        rexxhost = SetupARexxHost( basename );

        struct RexxHost *SetupARexxHost( char * );

   FUNCTION
        This function allocates and initializes a RexxHost
        structure. It opens a public message port under the
        given basename. If no basename (NULL) was specified,
        the default basename as entered in the ARexxBox window
        will be used instead.
        
        Anyway, if a public port of that name already exists,
        SetupARexxHost() will start adding numbers to the name
        until a unique name is found. So if for example the
        basename is "myhost" and there is already a port of that
        name in the system, the name will be changed to
        "myhost.1" (then to "myhost.2" and so on).
        
        The actual name will be copied to the portname field of
        the RexxHost structure. It is a good idea to tell the
        user about the actual port name of the new host.

   INPUTS
        basename - the messageport basename or NULL

   RESULTS
        rexxhost - the initialized RexxHost structure, ready to
                   go. Pass this pointer to CloseDownARexxHost(),
                   ARexxDispatch() and SendRexxCommand().

   SEE ALSO
        CloseDownARexxHost(), ARexxDispatch(), SendRexxCommand()


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

15.13 ARexxBox/StrDup

ARexxBox/StrDup                                               ARexxBox/StrDup

   NAME
        StrDup -- duplicate a string

   SYNOPSIS
        copy = StrDup( origin );

        char *StrDup( char * );

   FUNCTION
        This routine will do exactly the same as its standard C lib
        counterpart strdup(), but use the exec function AllocVec()
        for allocating the needed memory.
        
        (So YOU are responsible for freeing the copy!)

   INPUTS
        origin - the original string

   RESULTS
        copy - the copy of the original string

   SEE ALSO
        strdup(), exec.library/AllocVec(), exec.library/FreeVec()


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

16 File Format

The ARB file format is an extendable ASCII format (line separator is LF). Besides the obvious data (syntax of the commands, their arguments and results) an ARB file contains common and command specific tags.

The first line of an ARB file contains the ID string ARB. Beginning with line two comes the first, global tag block. Each tag line begins with a dollar followed without a space by the tag ID (type: long). The rest of the line contains alphanumeric parameters, separated by spaces.

Up to now there’s only one global tag ID:

The first line after this tag block contains the MsgPort base name. The next line contains the status of the CommandShell gadget (1 for checked). The following lines up to the end of the file are the command definitions. Each command entry is of the form:

There are currently two tag IDs for commands:

There will possibly be other tag IDs in the future, so please write an intelligent parser for the tag blocks. Unknown tags should be ignored.


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

17 History

History of ARexxBox Releases:

V0.99
    first beta release

V0.99a
    FIXED: Argument and result lists could work on an
    invalid command -> Enforcer-Hit/Crash.
    (Report: RALF_KAISER@AWORLD)

V0.99b
    ENHANCED: GadToolsBox source fixed to use the System Default
    Font instead of the Screenfont for Layout and Gadgets.
    (Report: SYSOP@INSIDER [Garry Glendown])

V0.99c
    FIXED: The equal sign '=' wasn't allowed for arguments.
    
    FIXED: After changing some argument or result, the display
    now shows the changed element, rather than the last one
    in that list.
    
    FIXED: The font routines still had some error.
    (Report: F.J.Reichert [F_J_REICHERT@SAARAG])

V0.99d
    FIXED: All pointer conversions are now clean. The code
    should now be compileable without warnings.
    Added pragma #includes and _toupper() for SAS/C.
    (Report: W_KUETING@HSP)
    
V0.99e
    FIXED: When _no_ result field was given, the code
    generated an "out of memory" error.
    
    ENHANCED: ReplyRexxCmd() now creates the variable RC2, it
    contains the "Secondary Returncode", which can be set in
    any rxif-structure under the name rc2. This variable can
    be used to return detailed error codes to the calling
    rexx program.
    
    This feature is an extension of the style guide conventions,
    IMHO a good one. If you have complaints or comments on 
    this idea, please tell me!
    
    RC2 will only be generated if a) 'options results' was given
    and b) RC != 0. The field rc2 may contain an error code (long)
    as well as an error string (char *). Code is the default.
    The software distinguishes these two types by the sign of
    rc, rc positive means rc2 is a long, rc negative means rc2
    is a char *.
    A negative rc will be converted to positive before beeing
    returned to the caller.
    
    Example for error CODE:
        rd->rc = 10;
        rd->rc2 = ERROR_OBJECT_NOT_FOUND;
    
    Example for error STRING:
        rd->rc = -10;
        rd->rc2 = (long) "You idiot! No object!";
    
    The standard error strings are _not_ localized. As soon as
    I get some infos and tools for this, I'll do it.

    ENHANCED: SendRexxCommand() now has a new parameter for
    better supporting the standard command "RX". It is a
    FileHandle (BPTR!), which becomes the stdin/stdout of
    the executed arexx script. FreeRexxCommand() closes
    the file (if necessary).
    
    SendRexxCmd() now returns the address of the sent
    RexxMsg structure (or NULL for error).
    
    ENHANCED: The RexxHost structure now has a new field
    called "userdata". It can be used to hook the RexxHost
    onto your own structures, e.g. for linking hosts and
    and their project instances together.
    
    ENHANCED: Every command now has a global "enabled"
    flag. If the flag is 0, the dispatcher will not execute
    that command anymore until the flag will be set again.
    The user should have the ability to manipulate this flag
    using the (standard) arexx commands ENABLE and DISABLE
    (see rxif/*.c).
    
    CHANGED: Any CommandShell now must have its own RexxHost,
    that means that host _must_not_ be used as a normal ARexx
    port simultaneously.
    
    ENHANCED: As a consequence, every rxif function now gets
    the RexxHost of the ARexx port resp. CmdShell as it's
    (first) parameter. Therefore the function can decide
    whether it was called from ARexx or from a Shell and
    on which project it should work.
    
    ENHANCED: Another consequence is the new flag ARB_HF_CMDSHELL
    for supporting the standard command CMDSHELL. The flag is
    in the 'flags' field of the RexxHost structure. If it's
    set, that host is currently running a shell. You can
    clear the flag from anywhere causing the shell to close
    (after processing the next command).
    
    FIXED: ARB no longer accepts argument or result names
    consisting of only spaces or only options.
    
    CHANGED: As some rxif functions have to access them,
    the structs 'rxs_command' and 'rxs_commandlist' are now
    defined in the headerfile. For accessing the command
    list, there is a new function:
        struct rxs_command *FindRXCommand( char *name );
    
    FIXED: Arguments with '=' are now translated correctly
    into variable names for C. The last alias component
    will be used as the var name.
    
    ENHANCED: There is now a callback function for words
    the parser doesn't recognize:
        char *ExpandRXCommand( struct RexxHost *host,
                               char *commandline );
    This function will be called before the parser returns
    an error. If the function returns NULL, the error will be
    generated, if not, the parser assumes that the function
    was able to analyze the input and tries to parse the
    returned string.
    This function can be used to implement command aliases
    or processing of non-standard commands.
    
    Attention! ExpandRXCmd() has to allocate memory for the
    returned string, using standard C functions! This memory
    will be freed by the parser after processing the string!
    
    ENHANCED: ARB now does more safety checks on saving the
    source modules, so you should never accidentally destroy
    other code.
    
    NOTE: One of the standard commands as suggested by the
    style guide uses the keywords "VAR" and "STEM" to
    describe the INPUT variables instead of the former
    usage as OUTPUT descriptors. I don't think this is a
    good choice as there can't be any results from this
    function that way. I suggest other names for those
    arguments, e.g. "FROMVAR" and "FROMSTEM".
    Comments?
    
    (The ARB doesn't look at the already existing args, if
    a command has some result, "VAR" and "STEM" will be
    added to the template.)
    
    Some of the style guide suggestions are not very precise
    and need extensions to operate correctly. I added some
    extensions to the arexx standard commands. Comments
    welcome.
    
    FIXED: Numeric results now work.

V0.99f
    ENHANCED: ARB now uses two FileRequesters, one for the
    binaries and the other for sources. The patterns now
    remain what you set them to and have defaults with #?
    instead of *.
    (Report: Stefan Zeiger)
    
    FIXED: Window->TopEdge is now font sensitive.
    (Report: Stefan Zeiger)
    
V0.99g
    FIXED: The parser now returns the ReadArgs() error code
    in rc2.
    
    CHANGED: No longer appends \n to the template string
    before parsing (not needed).
    
    CHANGED: The ARexxBox now uses the ASL file requester.
    (Wish: Garry Glendown [Sysop@Insider])
    
V1.00
    ENHANCED: Source now compatible to GCC. Remaining
    warnings may be ignored.
    
    CHANGED: FindRXCommand() now only accepts real abbreviations
    of commands.
    
--- FIRST PUBLIC RELEASE ---
    
V1.01
    ENHANCED: FindRXCommand() now uses binary search
    (so it's now complexity O(log n) instead of O(n))

V1.02
    ADDED: Clipboard support
    
    FIXED: CreateVAR() didn't check an allocation
    (Report: Rüdiger Dreier)
    
    CHANGED: SendRexxCommand() is now divided into two functions,
    CreateRexxCommand() and CommandToRexx(). So one can change a
    created msg if needed before sending it to ARexx.
    
    ENHANCED: Unknown commands will now be sent to ARexx before
    being treated as "unknown". External ARexx programs will be
    called in a transparent way with this method.
    (Suggestion: Rüdiger Dreier)
    
    ENHANCED: DoRXCommand() and DoShellCommand() polished a bit.
    (Report: Hartmut Goebel)
    
    FIXED: The dispatcher now checks incoming msgs.
    (Report: Hartmut Goebel)
    
    FIXED: In free_stemlist() was a potential FreeMem bug.
    
    CHANGED: Now using AllocVec/FreeVec instead of (m|c)alloc and free.
    Needed a new function as well, a replacement for strdup:
        char *StrDup( char *string )
    (Suggestion: Rüdiger Dreier)
    
    FIXED: The CloseDown could cause running scripts on that port to hang.
    (Report: Rüdiger Dreier)
    
V1.03
    ENHANCED: New parameter for the Box: FONT=<name>/<size>, specifies
    the font to use. Default is now again the Screen font (Style Guide).
    (Suggestion: Timothy J. Aston)

    CHANGED: If an empty port name was specified, the default will be used.
    (Suggestion: hartmut "Essich" Goebel)

    CHANGED: VAR and STEM parameters will now be converted to upper case,
    as SetRexxVar() doesn't do this by itself.
    (REXX standard)

V1.04
    FIXED: Path for project files will be kept when importing files via
    "Merge".
    (Report: Stefan Reisner)
    
    FIXED: ARG0 now casted to (char *) everywhere.
    (Report: Marc Schröer)
    
    ENHANCED: The header now has got it's own #define.
    (Marc Schröer)
    
V1.05
    ENHANCED: Source generation now intelligent, old interface functions
    will be recognized through special comments in the source and either be
    kept or moved to a storage file.
    (Suggestion: all.all; ID idea: Christoph Teuber)
    
    CHANGED: File format changed to reflect the new source generation.
    The Box will read the old format.
    
    ENHANCED: SetupARexxHost() now needs a second parameter: An optionally
    previously allocated MsgPort. So one can use a special port, e.g. to
    use one signal for all ARexx ports.
    (Suggestion: Stefan Reisner)
    
V1.10
    ENHANCED: The Oberon source generator is there at last. The
    Oberon source is completely by the Oberon Wizard Extraordinary
    hartmut "Essich" Goebel. Questions and comments concerning
    Oberon please go directly to him, as I don't know Oberon.
    
    ENHANCED: Implemented result hook method, if the variable
    ARexxResultHook contains the address of a function, it will be
    called for all replies to messages sent to ARexx.
    
    FIXED: FreeRexxCommand() no longer closes stdin and stdout if
    these were entered.

V1.11
    FIXED: Some last changes for Oberon.

----------- Release 2 -------------

V1.12
    FIXED: The HELP command produced Enforcer hits (strlen(0)).
    (Report: Klaas Hermanns)
    
    ENHANCED: Introduced tag #2 for commands: External status flag,
    "New" state of this flag will only be reset by external programs,
    e.g. documentation aids like ARB2TeXinfo by Albert Weinert.
    (Suggestion: Albert Weinert)
    
    FIXED: The command list was generated not alphabetically but
    numerically sorted (by their IDs).
    (Report: Klaas Hermanns)
    
    ENHANCED: Instead of the binary search algorithm, the Box now
    generates a real finite state machine for searching of commands
    (FindRXCommand). The binary search method had a big design flaw
    with abbreviations on the alphabetically sorted list of commands.
    (ATT: This has been implemented for C only up to now!)
    (Report: Klaas Hermanns)
    
    FIXED: For SAS C, toupper() will be #undefined. Also there is now
    the real function cast in the list of commands.
    (Report: Klaas Hermanns)
    
    FIXED: The MIN and MAX results of Misc.arb/GETATTR have to be
    numbers, of course.
    (Report: Klaas Hermanns)
    
    FIXED: "Merge" trashed the command list when merging in existing
    commands.
    
    CHANGED: Now declares the external library bases with their
    appropriate types (C).
    (Wunsch: Klaas Hermanns)
    
    CHANGED: In arb/advanced.arb, commands REQUESTNUMBER and
    REQUESTSTRING, I changed the argument called "DEFAULT" to "DEFAULTNUM"
    resp. "DEFAULTSTR" to avoid conflicts with the 'default' keyword in C.
    (Report: Klaas Hermanns)
    
    ENHANCED: There's now another parameter for all interface functions
    called "struct RexxMsg *rexxmsg", which will contain the address of
    the message from REXX if called by ARexx. If called from a command
    shell, it will contain NULL, so you can also use it to determine the
    caller. This is to support GetRexxVar(), which needs this pointer.
    (Report: Klaas Hermanns)
    
    FIXED: I now define toupper() as a function for GCC. The macro caused
    problems by evaluating the parameter more than once.

    FIXED: The command shell parameter parsing had a bug (the ReadArgs
    buffer wasn't cleared).
    
----------- Release 3 -------------

[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

18 Thanks

I’d like to thank the following persons:


[ << ] [ < ] [ Up ] [ > ] [ >> ]         [Top] [Contents] [Index] [ ? ]

Index

Jump to:   A   B   C   D   E   F   G   H   I   K   L   M   O   P   R   S   T   U   V  
Index Entry  Section

A
Addresses 2 Addresses of the Authors
amiga.lib 4.3 C source
amiga.lib 4.3 C source
ANSI C 4.3 C source
ARB input 6.1 Input
ARexxBox/ARexxDispatch 15.1 ARexxBox/ARexxDispatch
ARexxBox/CloseDownARexxHost 15.2 ARexxBox/CloseDownARexxHost
ARexxBox/CommandShell 15.3 ARexxBox/CommandShell
ARexxBox/CommandToRexx 15.4 ARexxBox/CommandToRexx
ARexxBox/CreateRexxCommand 15.5 ARexxBox/CreateRexxCommand
ARexxBox/DoShellCommand 15.6 ARexxBox/DoShellCommand
ARexxBox/ExpandRXCommand 15.7 ARexxBox/ExpandRXCommand
ARexxBox/FindRXCommand 15.8 ARexxBox/FindRXCommand
ARexxBox/FreeRexxCommand 15.9 ARexxBox/FreeRexxCommand
ARexxBox/ReplyRexxCommand 15.10 ARexxBox/ReplyRexxCommand
ARexxBox/SendRexxCommand 15.11 ARexxBox/SendRexxCommand
ARexxBox/SetupARexxHost 15.12 ARexxBox/SetupARexxHost
ARexxBox/StrDup 15.13 ARexxBox/StrDup
Arguments 10.1 Arguments
ATT: Interface changed! 6.6 Generate Source

B
Bug reports 2 Addresses of the Authors

C
CommandShell 6.3 CommandShell
Comments 8.3 ARB special comments
Concept 7 Concept
Concept: Closedown 7.5 Closedown
Concept: Commands to ARexx 7.4 Commands to ARexx
Concept: Expanding commands 7.3 Expanding commands
Concept: Init 7.1 Initializing
Copy 6.7 Clipboard
Cut 6.7 Clipboard

D
Data structure 9.1 Basics
Design questions 12.1 Design questions

E
E-Mail 2 Addresses of the Authors
Erase 6.7 Clipboard
Error Codes 11 Error Codes
Example test 12.2 Example

F
Features 3 Introduction
File Format 16 File Format
FreeWare 1 Important remarks

G
Generate Source 6.6 Generate Source
Gifts 2 Addresses of the Authors

H
History 17 History
How to use the Code 12 How to use the generated Code

I
Important remarks 1 Important remarks
Interface Functions 9 Interface Functions
Interface structure 9.1 Basics
InterNet Address 2 Addresses of the Authors

K
Konzept: Commands from ARexx 7.2 Commands from ARexx

L
Local Memory 9.2 Local Memory

M
Mail Address 2 Addresses of the Authors
Mark Range 6.7 Clipboard
Merge in 6.4 Merge in
MsgPort Basename 6.2 MsgPort Basename

O
Oberon-2 13 Hints concerning the Oberon-2 source
OLink 4.4 Oberon-2 source

P
Paste 6.7 Clipboard
Print 6.5 Print

R
RC 11 Error Codes
RC2 11 Error Codes
ReadArgs 10.1 Arguments
ReadArgs 14 ReadArgs
ReadArgs: More Features 14.3 More Features
ReadArgs: Results 14.2 Results
ReadArgs: Template syntax 14.1 Template syntax
reqtools.library 4.2 Software
RESULT 10 Arguments & Results
Results 10.2 Results
rexxvars.o 4.3 C source
RVI 4.4 Oberon-2 source
rxif examples 9.3 Examples

S
Shortcuts 6.1 Input
Software layers 12.1 Design questions
Source: ARB comments 8.3 ARB special comments
Source: C 8.1 C
Source: Oberon 8.2 Oberon
static 9.2 Local Memory
STEM 10 Arguments & Results
Suggestions 2 Addresses of the Authors

T
Thanks 18 Thanks
Transfer structure 9.1 Basics
Types 10.2 Results

U
up & do 6.1 Input

V
VAR 10 Arguments & Results

Jump to:   A   B   C   D   E   F   G   H   I   K   L   M   O   P   R   S   T   U   V  

[Top] [Contents] [Index] [ ? ]

Footnotes

(1)

The Oberon-2 source was designed to be object oriented and “type-save”.

(2)

I think the generic procedures in ARBRexxHost (especially ARBRexxHost.CreatStem) do an elegant job on this problem. I recommend you have a look at them.


[Top] [Contents] [Index] [ ? ]

Table of Contents


[Top] [Contents] [Index] [ ? ]

About This Document

This document was generated on July 23, 2024 using texi2html 5.0.

The buttons in the navigation panels have the following meaning:

Button Name Go to From 1.2.3 go to
[ << ] FastBack Beginning of this chapter or previous chapter 1
[ < ] Back Previous section in reading order 1.2.2
[ Up ] Up Up section 1.2
[ > ] Forward Next section in reading order 1.2.4
[ >> ] FastForward Next chapter 2
[Top] Top Cover (top) of document  
[Contents] Contents Table of contents  
[Index] Index Index  
[ ? ] About About (help)  

where the Example assumes that the current position is at Subsubsection One-Two-Three of a document of the following structure:


This document was generated on July 23, 2024 using texi2html 5.0.