home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 1: Amiga
/
FrozenFish-Apr94.iso
/
bbs
/
alib
/
d5xx
/
d599
/
rxilshell.lha
/
RxilShell
/
src.lzh
/
rxil_shell.c
next >
Wrap
C/C++ Source or Header
|
1992-01-30
|
18KB
|
582 lines
/***************************************************************************
Program:
File: Rxil_Shell.c
Version: V1.0
Date: 13.12.91
Function: Provide a friendly shell for the Rxil ARexx library
Copyright: SciTech Software 1991
Author: Andrew C. R. Martin
Address: SciTech Software
23, Stag Leys,
Ashtead,
Surrey,
KT21 2TD.
Phone: +44 (0372) 275775
EMail: UUCP: cbmuk!cbmuka!scitec!amartin
JANET: andrew@uk.ac.ox.biop
****************************************************************************
This program is not in the public domain, but it may be freely copied
and distributed for no charge providing this header is included.
The code may be modified as required, but any modifications must be
documented so that the person responsible can be identified. If someone
else breaks this code, I don't want to be blamed for code that does not
work! The code may not be sold commercially without prior permission from
the author, although it may be given away free with commercial products,
providing it is made clear that this program is free and that the source
code is provided with the program.
****************************************************************************
Description:
============
* The Rxil library makes calls to ARexx far easier. Error handling, etc.
is done for the programmer. Rxil_Shell makes these calls even easier.
Some flexibility is missing from these calls (although, when needed,
this can be re-introduced by direct calls to Rxil or ARexx itself).
* The following Rxil routines have been modified:
RxilCheckPort() Fix to memory allocation. ARG0() macro was getting
expanded wrongly causing MungWall hits.
display_message() Changed call to AutoRequest() to use MyAutoRequest()
which looks nicer under V1.3
RxilHandleReturn() Given a second parameter to control internal display
of returns from functions. Also returns a flag to
indicate whether a return value was obtained.
* The Rexx command table, an array of RxilFunction's must be created and
passed to SetupREXX(). A line of NULL's and 0's is used to mark the end
of the table. For example:
struct RxilFunction rexx_cmd_table[] = {
{ "help", &rexx_parse, 0, 10, FALSE, RXIL_PUBLIC },
{ "quit", &rexx_parse, 0, 10, FALSE, RXIL_PUBLIC },
{ "command",&cmd_launch_cmd, 0, 1, FALSE, RXIL_PUBLIC },
{ "func", &cmd_launch_func, 0, 16, FALSE, RXIL_PUBLIC },
{ NULL, NULL, 0, 0, FALSE, 0 }
};
The structure members are:
(char *) Command name (in lower case)
(void *)() Function to be called for this command
int Min number of arguments required
int Max number of arguments required
BOOL Should command matching be case sensitive
int Privilege. RXIL_PUBLIC or RXIL_SECRET. Specifies which port
the command is valid from. If REXX_PUBLIC, command may be
executed through either port.
* The functions specified in the command table are called with a single
parameter, a pointer to a RexxMsg structure. The example command table
shows 2 calls to rexx_parse(). This implies an additional layer of
parsing is supplied by the client program. If required, the routine
BuildComLine() may be called in such a parser to rebuild the command
line. The following example shows how this might be done:
void rexx_parse(struct RexxMsg *rexxmsg)
{ char buffer[200];
BuildComLine(buffer); Rebuild the command line
Interpret(buffer); Call our own parser
}
* The only Rexx specific external which needs to be specified by the client
program (and then only if the client is interested in returns from
macros) is:
extern char *Rexx_return;
****************************************************************************
Usage:
======
SetupREXX(portname, extension, conspec, synch, comtab, startup)
---------------------------------------------------------------
Input: char *portname Port name
char *extension Default extension
NULL: "rexx"
else: taken a string pointer
char *conspec Console spec for macros to use.
NULL: none (use CLI)
1: default
else: taken a string pointer
int synch Are macros to be synchronous?
0: Synchronous
1: Asynchronous
struct RxilFunction comtab[] ARexx command table (see above)
char *startup Name of Startup macro
NULL: No startup
Returns: void
Sets up public and private REXX ports and specifies various parameters
for Rexx. Also runs a startup macro if required; thus any other
preparation routines should be called before SetupREXX().
comtab[] should be prepared as shown above.
ProcessReturns()
----------------
Input: void
Returns: void
This routine is for programs which launch macros. Handles any ARexx
invocation returns which may be back. Informs of any problems and
allocates and sets the Rexx_return string if a function returned
with a value.
CloseREXX(wind, force)
----------------------
Input: struct Window *wind Pointer to window
int force 0: Don't force; 1: Do force
Returns: int 0: Didn't close; 1: Did
Clean up all REXX stuff. Unless force is set, will ask whether it
should proceed IF there are any macros waiting. This is done by posting
a requester in wind (or Workbench if wind is NULL).
LaunchCmd(buf)
--------------
Input: char *buf Command macro to be launched
Returns: void
Launch a REXX command.
SetFuncParam(pos, string)
-------------------------
Input: int pos Parameter number (0--15)
char *string Parameter string
Returns: int 0: OK; 1: Failed
Allocate space to put a function parameter and copy in the parameter
string. The name of the function to be called should be placed in
position 0. Returns 0 if succeeded; 1 if not
LaunchFunc()
------------
Input: void
Returns: void
Launch a REXX function. Uses data created by calls to SetFuncParam()
RexxReturnUsed()
----------------
Input: void
Returns: void
Free memory used for Rexx_return. Also sets Rexx_return back to NULL
so its value can be tested to see of we've got a value back from a
function call.
BuildComLine(buffer)
--------------------
Output: char *buffer Pointer to character string
Returns: void
Rebuilds the command line into buffer (which must be pre-allocated).
This is useful if you want to parse commands separately from the
built-in parser.
****************************************************************************
Revision History:
=================
***************************************************************************/
/* Includes
*/
#include "rxil.h"
#include <graphics/gfxbase.h>
#include <libraries/dos.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#ifdef LATTICE
#include <proto/intuition.h>
#endif
/************************************************************************/
/* Intuition Externs
*/
extern struct IntuitionBase *IntuitionBase;
extern struct GfxBase *GfxBase;
/************************************************************************/
/* REXX-specific extern defines. These are required by other rxil routines
and/or by client code.
*/
/* This is the Rxil definition structure.
*/
struct RxilDef *global_rdef = NULL;
/* This is used to place return values from functions
*/
char *Rexx_return = NULL;
/************************************************************************/
/* REXX-specific static defines. These are only required by routines
defined in this file.
*/
/* We provide one invocation structure for commands and one for functions.
These could be allocated and deallocated on the fly.
*/
static struct RxilInvocation *rxi_func;
static struct RxilInvocation *rxi_cmd;
/* This one is for the startup macro. We want to retain it's pointer
even after it is launched so that we can recognise it when it
terminates and handle it differently.
*/
static struct RxilInvocation *rxi_startup;
/* This is used to build REXX function arguments
*/
static char *RexxFuncBuf[16] = {NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL};
/************************************************************************/
/* Setup the REXX port
*/
void SetupREXX(char *portname, /* Port name */
char *extension, /* Default extension 0: "rexx" */
char *conspec, /* CON: 0: none, 1: default, or string */
int synch, /* 0: Synchronous, 1: Asynchronous */
struct RxilFunction comtab[], /* REXX command table */
char *startup) /* Startup macro */
{
/* Open rexx library and desired ports.
Only the PUBLIC port is needed if we're only receiving commands
*/
global_rdef = RxilInit(RXIL_PUBLIC | RXIL_SECRET, portname);
if(global_rdef == NULL)
{
Die("Unable to init rexx");
}
/* Initialise RxilDef to customise things.
Here, we could set
global_rdef->Flags
to turn features off.
*/
global_rdef->Flags = RXIL_NO_ABORT;
/* Set up console for commands or functions launced by this program.
If conspec was 0, we do this from a CLI;
if 1, we use a standard spec;
else, this is a pointer to a string for the required CON:
*/
if(conspec == (char *)0L)
global_rdef->Console = NULL;
else if(conspec == (char *)1L)
global_rdef->Console = "CON:10/10/400/150/RexxCon";
else
global_rdef->Console = conspec;
/* Set the default extension for macros */
if(extension == (char *)0L)
global_rdef->Extension = "rexx";
else
global_rdef->Extension = extension;
/* The port to use for launched commands.
REXX: synchronous
AREXX: asynchronous
*/
if(synch == 0)
global_rdef->HostPort = "REXX";
else
global_rdef->HostPort = "AREXX";
/* The command table we've created
*/
global_rdef->CommandTable = &comtab[0];
/***
Pre-allocate the command and function some invocation structures.
These could be allocated and de-allocated on-the-fly if desired.
***/
rxi_cmd = RxilCreateRxi(NULL, RXCOMM);
if(rxi_cmd == NULL)
{
Die("Unable to allocate command_rxi");
}
rxi_func = RxilCreateRxi(NULL, RXFUNC);
if( rxi_func == NULL )
{
Die("Unable to allocate function_rxi");
}
/***
Run a startup macro when the program is invoked
***/
rxi_startup = NULL;
if(startup)
{
rxi_startup = RxilCreateRxi(startup, RXCOMM);
if(rxi_startup == NULL)
{
/* We don't die, just give a message */
ReqMessage(NULL,"** Unable to allocate startup rxi **",0);
}
else
{
/* We don't need a console */
rxi_startup->Console = NULL;
/* Now launch the macro */
if(RxilLaunch( rxi_startup ) != 0)
{
/* We don't die, just give a message */
ReqMessage(NULL,"** Unable to launch the startup macro **",0);
}
}
}
}
/************************************************************************/
/* This code is for programs which launch macros.
Handle any ARexx invocation returns which may be back.
*/
void ProcessReturns(void)
{
struct RxilInvocation *rxi;
while((rxi = RxilGetReturn()) != NULL)
{
#ifdef DEBUG2
if(rxi->Type == RXCOMM)
{
printf("Command Invocation completed\n");
}
else
{
printf( "Function Invocation completed\n" );
}
#endif
if(rxi == rxi_startup)
{
/* This is our startup macro terminating. We handle this
differently since we don't want to display an error
if not found (which the standard routine
RxilHandleReturn() would do). We also want to de-allocate
the RxilInvocation structure.
*/
/* Deallocate things, close console windows, etc.
Then free the structure.
*/
if((rxi->RexxMsg->rm_Result1 != RC_WARN) ||
(rxi->RexxMsg->rm_Result2 != ERR10_001))
{
/* The error is not just "program not found".
It is a real error, so tell the user.
ACRM: surely, this should be &&, not || !)
*/
RxilHandleReturn(rxi, 1);
}
RxilCleanupReturn(rxi);
RxilDeleteRxi(rxi);
rxi_startup = NULL; /* To be tidy... */
}
else
{
/* This is a macro other than the startup, so handle the
return normally, telling the user about any problems.
Nothing will break if this code is removed...
*/
if(Rexx_return) FreeMem(Rexx_return, (strlen(Rexx_return) + 2));
Rexx_return = NULL;
if(RxilHandleReturn(rxi, 0))
{
Rexx_return = (char *)
AllocMem((strlen((char *)(rxi->RexxMsg->rm_Result2)) + 2), 0L);
if(Rexx_return)
strcpy(Rexx_return, (char *)(rxi->RexxMsg->rm_Result2));
}
/* Clean up: deallocate memory and close CON: */
RxilCleanupReturn(rxi);
}
}
}
/************************************************************************/
/* Clean up all REXX stuff. Unless force is set, will ask whether it
should proceed if there are any macros waiting.
Returns 1 if it cleaned up OK; otherwise returns 0.
*/
int CloseREXX(struct Window *wind,
int force)
{
int cleanup = 1,
i;
if(!force)
{
if(RxilPending())
cleanup = ReqMessage3(wind,"There are REXX commands pending"," ",
"Really quit?",1);
}
if(cleanup)
{
/* Clean up the rxil stuff */
RxilCleanup(global_rdef);
global_rdef = NULL;
/* Clean up additional rxil_shell stuff */
if(Rexx_return) FreeMem(Rexx_return, (strlen(Rexx_return) + 2));
Rexx_return = NULL;
for(i=0; i<16; i++)
{
if(RexxFuncBuf[i] != NULL)
FreeMem(RexxFuncBuf[i], (strlen(RexxFuncBuf[i]) + 2));
RexxFuncBuf[i] = NULL;
}
}
return(cleanup);
}
/************************************************************************/
/* Launch a REXX command
*/
void LaunchCmd(char *buf)
{
LONG rc;
rxi_cmd->Name = buf;
rc = RxilLaunch( rxi_cmd );
if(rc)
{
char buffer[80];
sprintf(buffer,"Command launch returned %d",rc);
ReqMessage2(NULL,buf,buffer,0);
}
}
/************************************************************************/
/* Allocate a space to put a function parameter
*/
int SetFuncParam(int pos,
char *string)
{
if(pos < 0 || pos > 15) return(1);
if(string != NULL)
{
/* If currently allocated, free it */
if(RexxFuncBuf[pos] != NULL)
FreeMem(RexxFuncBuf[pos], (strlen(RexxFuncBuf[pos]) + 2));
/* Reallocate for our string */
RexxFuncBuf[pos] = (char *)AllocMem((strlen(string) + 2), 0L);
if(RexxFuncBuf[pos] == NULL) Die("No memory for Rexx buffer");
/* Copy in our string */
strcpy(RexxFuncBuf[pos], string);
/* Free up the next position too */
if((pos + 1) < 16)
{
if(RexxFuncBuf[pos+1] != NULL)
FreeMem(RexxFuncBuf[pos+1], (strlen(RexxFuncBuf[pos+1]) + 2));
RexxFuncBuf[pos+1] = NULL;
}
}
return(0);
}
/************************************************************************/
/* Launch a REXX function
*/
void LaunchFunc(void)
{
int i;
LONG rc;
/* Set the Name to point to our allocated function name string */
rxi_func->Name = RexxFuncBuf[0];
/* Set the FuncArg[] array to point to our allocated strings */
for(i=1; i<16; i++)
{
/* First set to NULL */
rxi_func->FuncArg[i] = NULL;
/* Break if this is the last one */
if(RexxFuncBuf[i] == NULL) break;
/* Otherwise copy in the pointer */
rxi_func->FuncArg[i] = RexxFuncBuf[i];
}
/* Launch the function */
rc = RxilLaunch( rxi_func );
if(rc)
{
char RexxFuncBuffer[80];
sprintf(RexxFuncBuffer,"Function launch returned %d",rc);
ReqMessage2(NULL,RexxFuncBuf,RexxFuncBuffer,0);
}
}
/************************************************************************/
/* Free memory used for Rexx_return.
*/
void RexxReturnUsed(void)
{
Rexx_return = NULL;
}
/************************************************************************/
/* Rebuild the command line if a separate command parser is being used
*/
void BuildComLine(char *buffer)
{
int i;
buffer[0] = '\0';
for(i=0; i<RXIL_ARGC; i++)
{
strcat(buffer, RXIL_ARGV(i));
strcat(buffer," ");
}
}