home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 1: Amiga
/
FrozenFish-Apr94.iso
/
bbs
/
alib
/
d5xx
/
d539
/
simplerexx.lha
/
SimpleRexx
/
SimpleRexx.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-08-26
|
10KB
|
420 lines
/*
* Simple ARexx interface by Michael Sinz
*
* This is a very "Simple" interface to the world of ARexx...
* For more complex interfaces into ARexx, it is best that you
* understand the functions that are provided by ARexx.
* In many cases they are more powerful than what is presented
* here.
*
* This code is fully re-entrant and self-contained other than
* the use of SysBase/AbsExecBase and the ARexx RVI support
* library which is also self-contained...
*/
#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/ports.h>
#include <exec/memory.h>
#include <proto/exec.h>
#include <rexx/storage.h>
#include <rexx/rxslib.h>
#include <string.h>
#include <ctype.h>
/*
* The prototypes for the few ARexx functions we will call...
*/
struct RexxMsg *CreateRexxMsg(struct MsgPort *,char *,char *);
void *CreateArgstring(char *,long);
void DeleteRexxMsg(struct RexxMsg *);
void DeleteArgstring(char *);
BOOL IsRexxMsg(struct Message *);
/*
* Pragmas for the above functions... (To make this all self-contained...)
* If you use RexxGlue.o, this is not needed...
*
* These are for Lattice C 5.x (Note the use of RexxContext->RexxSysBase)
*/
#pragma libcall RexxContext->RexxSysBase CreateRexxMsg 90 09803
#pragma libcall RexxContext->RexxSysBase CreateArgstring 7E 0802
#pragma libcall RexxContext->RexxSysBase DeleteRexxMsg 96 801
#pragma libcall RexxContext->RexxSysBase DeleteArgstring 84 801
#pragma libcall RexxContext->RexxSysBase IsRexxMsg A8 801
/*
* Prototypes for the RVI ARexx calls... (link with RexxVars.o)
*/
__stdargs long CheckRexxMsg(struct RexxMsg *);
__stdargs long GetRexxVar(struct RexxMsg *,char *,char **);
__stdargs long SetRexxVar(struct RexxMsg *,char *,char *,long);
/*
* Now, we have made the pragmas needed, let's get to work...
*/
/*
* A structure for the ARexx handler context
* This is *VERY* *PRIVATE* and should not be touched...
*/
struct ARexxContext
{
struct MsgPort *ARexxPort; /* The port messages come in at... */
struct Library *RexxSysBase; /* We will hide the library pointer here... */
long Outstanding; /* The count of outstanding ARexx messages... */
char PortName[24]; /* The port name goes here... */
char ErrorName[28]; /* The name of the <base>.LASTERROR... */
char Extension[8]; /* Default file name extension... */
};
#define AREXXCONTEXT struct ARexxContext *
#include "SimpleRexx.h"
/*
* This function returns the port name of your ARexx port.
* It will return NULL if there is no ARexx port...
*
* This string is *READ ONLY* You *MUST NOT* modify it...
*/
char *ARexxName(AREXXCONTEXT RexxContext)
{
register char *tmp=NULL;
if (RexxContext) tmp=RexxContext->PortName;
return(tmp);
}
/*
* This function returns the signal mask that the Rexx port is
* using. It returns NULL if there is no signal...
*
* Use this signal bit in your Wait() loop...
*/
ULONG ARexxSignal(AREXXCONTEXT RexxContext)
{
register ULONG tmp=NULL;
if (RexxContext) tmp=1L << (RexxContext->ARexxPort->mp_SigBit);
return(tmp);
}
/*
* This function returns a structure that contains the commands sent from
* ARexx... You will need to parse it and return the structure back
* so that the memory can be freed...
*
* This returns NULL if there was no message...
*/
struct RexxMsg *GetARexxMsg(AREXXCONTEXT RexxContext)
{
register struct RexxMsg *tmp=NULL;
register short flag;
if (RexxContext)
if (tmp=(struct RexxMsg *)GetMsg(RexxContext->ARexxPort))
{
if (tmp->rm_Node.mn_Node.ln_Type==NT_REPLYMSG)
{
/*
* If we had sent a command, it would come this way...
*
* Since we don't in this simple example, we just throw
* away anything that looks "strange"
*/
flag=FALSE;
if (tmp->rm_Result1) flag=TRUE;
/*
* Free the arguments and the message...
*/
DeleteArgstring(tmp->rm_Args[0]);
DeleteRexxMsg(tmp);
RexxContext->Outstanding-=1;
/*
* Return the error if there was one...
*/
tmp=flag ? REXX_RETURN_ERROR : NULL;
}
}
return(tmp);
}
/*
* Use this to return a ARexx message...
*
* If you wish to return something, it must be in the RString.
* If you wish to return an Error, it must be in the Error.
* If there is an error, the RString is ignored.
*/
void ReplyARexxMsg(AREXXCONTEXT RexxContext,struct RexxMsg *rmsg,
char *RString,LONG Error)
{
if (RexxContext) if (rmsg) if (rmsg!=REXX_RETURN_ERROR)
{
rmsg->rm_Result2=0;
if (!(rmsg->rm_Result1=Error))
{
/*
* if you did not have an error we return the string
*/
if (rmsg->rm_Action & (1L << RXFB_RESULT)) if (RString)
{
rmsg->rm_Result2=(LONG)CreateArgstring(RString,
(LONG)strlen(RString));
}
}
/*
* Reply the message to ARexx...
*/
ReplyMsg((struct Message *)rmsg);
}
}
/*
* This function will set an error string for the ARexx
* application in the variable defined as <appname>.LASTERROR
*
* Note that this can only happen if there is an ARexx message...
*
* This returns TRUE if it worked, FALSE if it did not...
*/
short SetARexxLastError(AREXXCONTEXT RexxContext,struct RexxMsg *rmsg,
char *ErrorString)
{
register short OkFlag=FALSE;
if (RexxContext) if (rmsg) if (CheckRexxMsg(rmsg))
{
/*
* Note that SetRexxVar() has more than just a TRUE/FALSE
* return code, but for this "basic" case, we just care if
* it works or not.
*/
if (!SetRexxVar(rmsg,RexxContext->ErrorName,ErrorString,
(long)strlen(ErrorString)))
{
OkFlag=TRUE;
}
}
return(OkFlag);
}
/*
* This function will send a string to ARexx...
*
* The default host port will be that of your task...
*
* If you set StringFile to TRUE, it will set that bit for the message...
*
* Returns TRUE if it send the message, FALSE if it did not...
*/
short SendARexxMsg(AREXXCONTEXT RexxContext,char *RString,
short StringFile)
{
register struct MsgPort *RexxPort;
register struct RexxMsg *rmsg;
register short flag=FALSE;
if (RexxContext) if (RString)
{
if (rmsg=CreateRexxMsg(RexxContext->ARexxPort,
RexxContext->Extension,
RexxContext->PortName))
{
rmsg->rm_Action=RXCOMM | (StringFile ?
(1L << RXFB_STRING):0);
if (rmsg->rm_Args[0]=CreateArgstring(RString,
(LONG)strlen(RString)))
{
/*
* We need to find the RexxPort and this needs
* to be done in a Forbid()
*/
Forbid();
if (RexxPort=FindPort(RXSDIR))
{
/*
* We found the port, so put the
* message to ARexx...
*/
PutMsg(RexxPort,(struct Message *)rmsg);
RexxContext->Outstanding+=1;
flag=TRUE;
}
else
{
/*
* No port, so clean up...
*/
DeleteArgstring(rmsg->rm_Args[0]);
DeleteRexxMsg(rmsg);
}
Permit();
}
else DeleteRexxMsg(rmsg);
}
}
return(flag);
}
/*
* This function closes down the ARexx context that was opened
* with InitARexx...
*/
void FreeARexx(AREXXCONTEXT RexxContext)
{
register struct RexxMsg *rmsg;
if (RexxContext)
{
/*
* Clear port name so it can't be found...
*/
RexxContext->PortName[0]='\0';
/*
* Clean out any outstanding messages we had sent out...
*/
while (RexxContext->Outstanding)
{
WaitPort(RexxContext->ARexxPort);
while (rmsg=GetARexxMsg(RexxContext))
{
if (rmsg!=REXX_RETURN_ERROR)
{
/*
* Any messages that come now are blown
* away...
*/
SetARexxLastError(RexxContext,rmsg,
"99: Port Closed!");
ReplyARexxMsg(RexxContext,rmsg,
NULL,100);
}
}
}
/*
* Clean up the port and delete it...
*/
if (RexxContext->ARexxPort)
{
while (rmsg=GetARexxMsg(RexxContext))
{
/*
* Any messages that still are coming in are
* "dead" We just set the LASTERROR and
* reply an error of 100...
*/
SetARexxLastError(RexxContext,rmsg,
"99: Port Closed!");
ReplyARexxMsg(RexxContext,rmsg,NULL,100);
}
DeletePort(RexxContext->ARexxPort);
}
/*
* Make sure we close the library...
*/
if (RexxContext->RexxSysBase)
{
CloseLibrary(RexxContext->RexxSysBase);
}
/*
* Free the memory of the RexxContext
*/
FreeMem(RexxContext,sizeof(struct ARexxContext));
}
}
/*
* This routine initializes an ARexx port for your process
* This should only be done once per process. You must call it
* with a valid application name and you must use the handle it
* returns in all other calls...
*
* NOTE: The AppName should not have spaces in it...
* Example AppNames: "MyWord" or "FastCalc" etc...
* The name *MUST* be less that 16 characters...
* If it is not, it will be trimmed...
* The name will also be UPPER-CASED...
*
* NOTE: The Default file name extension, if NULL will be
* "rexx" (the "." is automatic)
*/
AREXXCONTEXT InitARexx(char *AppName,char *Extension)
{
register AREXXCONTEXT RexxContext=NULL;
register short loop;
register short count;
register char *tmp;
if (RexxContext=AllocMem(sizeof(struct ARexxContext),
MEMF_PUBLIC|MEMF_CLEAR))
{
if (RexxContext->RexxSysBase=OpenLibrary("rexxsyslib.library",
NULL))
{
/*
* Set up the extension...
*/
if (!Extension) Extension="rexx";
tmp=RexxContext->Extension;
for (loop=0;(loop<7)&&(Extension[loop]);loop++)
{
*tmp++=Extension[loop];
}
*tmp='\0';
/*
* Set up a port name...
*/
tmp=RexxContext->PortName;
for (loop=0;(loop<16)&&(AppName[loop]);loop++)
{
*tmp++=toupper(AppName[loop]);
}
*tmp='\0';
/*
* Set up the last error RVI name...
*
* This is <appname>.LASTERROR
*/
strcpy(RexxContext->ErrorName,RexxContext->PortName);
strcat(RexxContext->ErrorName,".LASTERROR");
/* We need to make a unique port name... */
Forbid();
for (count=1,RexxContext->ARexxPort=(VOID *)1;
RexxContext->ARexxPort;count++)
{
stci_d(tmp,count);
RexxContext->ARexxPort=
FindPort(RexxContext->PortName);
}
RexxContext->ARexxPort=CreatePort(
RexxContext->PortName,NULL);
Permit();
}
if ( (!(RexxContext->RexxSysBase))
|| (!(RexxContext->ARexxPort)) )
{
FreeARexx(RexxContext);
RexxContext=NULL;
}
}
return(RexxContext);
}