
/*
 * MINREXX.C
 *
 * By Radical Eye Software, slightly altered by me.
 */

static char *blurb = "Radical Eye MinRexx 0.4.jsh";

#include "jed.h"
#include "jed_protos.h"

Prototype   VALUE *		cmd_rexx	(LONG, VALUE *);
Prototype   LONG		upRexxPort	(STRPTR, STRPTR);
Prototype   VOID		dnRexxPort	(VOID);
Prototype   VOID		dispRexxPort	(VOID);
Local	    struct RexxMsg *	sendRexxCmd	(STRPTR, int(*)(), STRPTR, STRPTR, STRPTR, LONG);
Prototype   struct RexxMsg *	syncRexxCmd	(STRPTR, struct RexxMsg *);
Prototype   struct RexxMsg *	asyncRexxCmd	(STRPTR);
Prototype   struct RexxMsg *	asyncRexxString (STRPTR);
Prototype   VOID		replyRexxCmd	(struct RexxMsg *, LONG, LONG, STRPTR);
Local	    VOID		closeRexxLib	(VOID);
Local	    BOOL		openRexxLib	(VOID);
Local	    VOID		replytoit	(struct RexxMsg *);

/*
 * (rexx `m' `macroName')
 * (rexx `s' `rexxString')
 */
VALUE *
cmd_rexx(LONG argc, VALUE *argv)
{
    if(TPLATE2(VTF_STRING, VTF_STRING))
    {
	BOOL rc;
	if(*(argv[1].val_Value.String) == 'm')
	    rc = (BOOL)asyncRexxCmd(argv[2].val_Value.String);
	else
	    rc = (BOOL)asyncRexxString(argv[2].val_Value.String);
	setnumres(rc);
    }
    return(&RES);
}

#define MAXRXOUTSTANDING (300)
#define RXERRORIMGONE (100)
#define RXERRORNOCMD (30)

Local struct MsgPort *rexxPort;
Local BOOL bringerdown;
Local LONG stillNeedReplies;
Local LONG rexxPortBit;
Local STRPTR extension;
Local struct RexxMsg *oRexxMsg;

struct RxsLib *RexxSysBase;

/*
 *   This is the main entry point into this code.
 */
LONG
upRexxPort(STRPTR name, STRPTR exten)
{
    if(rexxPort == NULL)
    {
	Forbid();
	if(!(FindPort(name)))
	{
	    rexxPort = CreateMsgPort();
	    rexxPort->mp_Node.ln_Name = name;
	    rexxPort->mp_Node.ln_Pri = 1;
	    AddPort(rexxPort);
	}
	Permit();
	if(rexxPort)
	    rexxPortBit = 1L << rexxPort->mp_SigBit;
    }
    extension = exten;
    return(rexxPortBit);
}

Local VOID
closeRexxLib(VOID)
{
    if((!stillNeedReplies) && RexxSysBase)
    {
	CloseLibrary((struct Library *)RexxSysBase);
	RexxSysBase = NULL;
    }
}

VOID
dnRexxPort(VOID)
{
    if(rexxPort)
    {
	RemPort(rexxPort);
	bringerdown = TRUE;

	if(oRexxMsg)
	{
	    oRexxMsg->rm_Result1 = RXERRORIMGONE;
	    ReplyMsg((struct Message *)oRexxMsg);
	    oRexxMsg = NULL;
	}
	while(stillNeedReplies)
	{
	    WaitPort(rexxPort);
	    dispRexxPort();
	}
	closeRexxLib();
	DeleteMsgPort(rexxPort);
	rexxPort = NULL;
    }
    rexxPortBit = 0;
}

VOID
dispRexxPort(VOID)
{
    struct RexxMsg *RexxMsg;
    STRPTR cmd;
    BOOL dontreply;

    if(!rexxPort)
	return;

    while(RexxMsg = (struct RexxMsg *)GetMsg(rexxPort))
    {
    if(RexxMsg->rm_Node.mn_Node.ln_Type == NT_REPLYMSG)
	{
	    if (RexxMsg->rm_Args[1])
	    {
		((int (*)(struct RexxMsg *))(RexxMsg->rm_Args[1]))(RexxMsg);
	    }
	    DeleteArgstring(RexxMsg->rm_Args[0]);
	    DeleteRexxMsg(RexxMsg);
	    stillNeedReplies--;
	    closeRexxLib();
	}
	else
	{
	    cmd = (STRPTR)RexxMsg->rm_Args[0];
	    while (*cmd > 0 && *cmd <= ' ')
		cmd++;
	    RexxMsg->rm_Result1 = 0;
	    RexxMsg->rm_Result2 = 0;

	    dontreply = FALSE;

	    if(bringerdown)
		RexxMsg->rm_Result1 = RXERRORIMGONE;

	    else
	    {
		oRexxMsg = RexxMsg ;
		rxexecstring(cmd, RexxMsg);
	    }
	    oRexxMsg = NULL ;
	    if(!dontreply)
		ReplyMsg((struct Message *)RexxMsg) ;
	}
    }
}

Local BOOL
openRexxLib(VOID)
{
    if(RexxSysBase)
	return(TRUE);
    return((BOOL)(RexxSysBase = (struct RxsLib *)OpenLibrary(RXSNAME, 0L)));
}

Local struct RexxMsg *
sendRexxCmd(STRPTR s, int(*f)(), STRPTR p1, STRPTR p2, STRPTR p3, LONG m)
{
    struct MsgPort *rexxport;
    struct RexxMsg *RexxMsg;

    if((!rexxPort) || (stillNeedReplies > MAXRXOUTSTANDING-1))
	return(FALSE);
    RexxMsg = NULL;
    if(openRexxLib() && (RexxMsg =
	     CreateRexxMsg(rexxPort, extension, rexxPort->mp_Node.ln_Name)) &&
	     (RexxMsg->rm_Args[0] = CreateArgstring(s, (long)strlen(s))))
    {
	RexxMsg->rm_Action = RXCOMM | m;
	RexxMsg->rm_Args[1] = (STRPTR)f;
	RexxMsg->rm_Args[2] = p1;
	RexxMsg->rm_Args[3] = p2;
	RexxMsg->rm_Args[4] = p3;
	RexxMsg->rm_Node.mn_Node.ln_Name = RXSDIR;
	Forbid();
	if(rexxport = FindPort(RXSDIR))
	    PutMsg(rexxport, (struct Message *)RexxMsg);
	Permit();
	if(rexxport)
	{
	    stillNeedReplies++;
	    return(RexxMsg);
	}
	else
	    DeleteArgstring(RexxMsg->rm_Args[0]);
    }
    if(RexxMsg)
	DeleteRexxMsg(RexxMsg);
    closeRexxLib();
    return(FALSE);
}

struct RexxMsg *
asyncRexxCmd(STRPTR s)
{
    return(sendRexxCmd(s, NULL, NULL, NULL, NULL, NULL));
}

struct RexxMsg *
asyncRexxString(STRPTR s)
{
    return(sendRexxCmd(s, NULL, NULL, NULL, NULL, RXFF_STRING));
}

Local VOID
replytoit(struct RexxMsg *msg)
{
    struct RexxMsg *omsg;

    omsg = (struct RexxMsg *)(msg->rm_Args[2]);
    replyRexxCmd(omsg, msg->rm_Result1, msg->rm_Result2, NULL);
    ReplyMsg((struct Message *)omsg);
}

struct RexxMsg *
syncRexxCmd(STRPTR s, struct RexxMsg *msg)
{
    return(sendRexxCmd(s, replytoit, (char *)msg, NULL, NULL, NULL));
}

VOID
replyRexxCmd(struct RexxMsg *msg, LONG primary, LONG secondary, STRPTR string)
{
    if(!primary && (msg->rm_Action & (1L << RXFB_RESULT)))
    {
	if(string && openRexxLib())
	    secondary = (long)CreateArgstring(string, (long)strlen(string));
	else
	    secondary = 0L;
    }
    msg->rm_Result1 = primary;
    msg->rm_Result2 = secondary;
    closeRexxLib();
}

