home *** CD-ROM | disk | FTP | other *** search
- /***************************************************************************
-
- 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," ");
- }
- }