
/*
 *  REXX.C
 *
 *      (c) Copyright 1987 by Kim DeVaughn, All Rights Reserved
 *
 *  ARexx interface code, etc.
 *
 */

#include "defs.h"
#include <ctype.h>

Prototype void openrexx (void);
Prototype void closerexx (void);
Prototype void do_rx (void);
Prototype void do_rx1 (void);
Prototype void do_rx2 (void);
Prototype void do_rxImplied (char *, char *);
Prototype void do_rrexx(char *);
Prototype int do_rexx (char *, char *);
Prototype int Process_Rexx(void);
Prototype void PushMsg(struct RexxMsg *,struct RexxMsg *);
Prototype void PopMsg(struct RexxMsg *,int);


#if AREXX

#include <rexx/storage.h>
#include <rexx/rxslib.h>
#include <rexx/rexxio.h>
#include <rexx/errors.h>
#include "rexx.h"


int foundcmd;       /* control for implicit ARexx macro invocation   */
int cmderr;         /* global command error flag for do_rexx()'s use */
short InRxCmd;       /* main loop rexx processing inhibit */

#ifdef LATTICE
APTR CreateRexxMsg ARGS((PORT *, char *, char *));
void DeleteRexxMsg ARGS((struct RexxMsg *));
APTR CreateArgstring ARGS((char *, int));
void DeleteArgstring ARGS((struct RexxArg *));
int  IsRexxMsg ARGS((struct RexxMsg *));
void __stdargs InitPort ARGS((PORT *, char *));
void __stdargs FreePort ARGS((PORT *));
#else
__stkargs APTR CreateRexxMsg ARGS((PORT *, char *, char *));
__stkargs void DeleteRexxMsg ARGS((struct RexxMsg *));
__stkargs APTR CreateArgstring ARGS((char *, int));
__stkargs void DeleteArgstring ARGS((struct RexxArg *));
__stkargs int IsRexxMsg ARGS((struct RexxMsg *));
__stkargs void InitPort ARGS((PORT *, char *));
__stkargs void FreePort ARGS((PORT *));
#endif

struct RxsLib *RexxSysBase;
struct MsgPort *RexxPort;
char RexxHostName[16];
struct MacArray {
    struct NameArray *Next;
    struct RexxMsg *macs[16];
    struct RexxMsg *replies[16];
} *RexxPending = NULL;
static char macbuf[256];

static char RexBuf[256];
char RexBufUsed;

/*
 * initialization for ARexx ... just open rexsyslib.library (& open port ... TJM)
 */

void
openrexx()
{
    int DmeNum = 0;
/*     struct RexxArg *macarg;
       struct RexxMsg *macptr; */

    if(!(RexxSysBase = (struct RxsLib *)OpenLibrary("rexxsyslib.library", (ULONG)RXSVERS)))
        return;
    if(RexxPort = AllocMem(sizeof(struct MsgPort),MEMF_PUBLIC|MEMF_CLEAR)){
        strcpy(RexxHostName,"DME");
        Forbid();
        if(!FindPort(RexxHostName)) {
            InitPort(RexxPort, RexxHostName); /* error checking? */
            AddPort(RexxPort);
            Permit();
            NewDME = 1;
        }
        else {
            if(NewDME) {
                do {
                    sprintf(RexxHostName, "DME%d", DmeNum++);
                } while(FindPort(RexxHostName));
                InitPort(RexxPort, RexxHostName); /* error checking ? */
                AddPort(RexxPort);
            }
            Permit();
            if(!NewDME){ /* try to make sure user doesn't hit close gadget on old dme */
                FreeMem(RexxPort,sizeof(struct MsgPort));
                RexxPort = CreatePort(NULL,0);
                do_rrexx("\"'rxblock'\"");  /* if this doesn't succeed, then it's the user's own stupid fault.. */
            }
        }
    }
    else {
        CloseLibrary((struct Library *)RexxSysBase);
        RexxSysBase = NULL;
    }
    return;
}



/*
 * cleanup any open ARexx stuff ...  just close rexsyslib.library for now (& close port ... TJM)
 */

void
closerexx()
{
    if(RexxPort){
        if(!NewDME) {
            do_rrexx("\"'rxunblock'\"");
            DeletePort(RexxPort);
        }
        else {
            RemPort(RexxPort);
            FreePort(RexxPort);
        }
    }
    if (RexxSysBase)
        CloseLibrary((struct Library *)RexxSysBase);
}



/*
 *  explicit invocation interface between do_command() and do_rexx
 *  for ARexx macros having NO arguments (i.e., for the "rx" command)
 */

void
do_rx()
{
    do_rexx(av[1],RexxHostName);
}



/*
 *  explicit invocation interface between do_command() and do_rexx
 *  for ARexx macros having ONE argument (i.e., for the "rx1" command)
 */

void
do_rx1()
{

    strcpy(macbuf, av[1]);
    strcat(macbuf, " ");
    strcat(macbuf, av[2]);
    do_rexx(macbuf,RexxHostName);
}



/*
 *  explicit invocation interface between do_command() and do_rexx
 *  for ARexx macros having TWO arguments (i.e., for the "rx2" command)
 */

void
do_rx2()
{
    strcpy(macbuf, av[1]);
    strcat(macbuf, " ");
    strcat(macbuf, av[2]);
    strcat(macbuf, " ");
    strcat(macbuf, av[3]);
    do_rexx(macbuf,RexxHostName);
}



/*
 *  implicit invocation interface between do_command() and do_rexx
 *  for ARexx macros implicitly called; arbitrary number of arguments
 */

void
do_rxImplied(cmd, args)
char *cmd;
char *args;
{
    strcpy(macbuf, cmd);
    strcat(macbuf, " ");
    strcat(macbuf, args);
    do_rexx(macbuf,RexxHostName);
}

void
do_rrexx(mac)
char *mac;
{
    do_rexx(mac,"DME");
    WaitPort(RexxPort);
    GetMsg(RexxPort);
}

/*
 *  issue a command to ARexx ...
 */

static struct RexxMsg *CurRxMac;

int
do_rexx(macstr,hostname)
char *macstr,*hostname;
{
    struct RexxArg *macarg;

    struct MsgPort *ARexxPort;

    struct RexxMsg *macptr;
/*  struct RexxMsg *cmdptr;

    int  err;
    long oldLock;    */
    int  ret;


    if (RexxSysBase == 0) {
        title("Unknown Command   -   No Macros:  ARexx Not Installed ");   /* no rexxsyslib */
        return(0);
    }

    if (macarg = (struct RexxArg *)CreateArgstring(macstr, strlen(macstr))) {
        if (macptr = (struct RexxMsg *)CreateRexxMsg(RexxPort, "dme", hostname)) {
            ACTION(macptr) = RXCOMM;
            ARG0(macptr)   = (STRPTR)macarg;

            Forbid();
            if (ARexxPort = (struct MsgPort *)FindPort("REXX")) {
                PutMsg(ARexxPort, (MSG *)macptr);
                Permit();
                CurRxMac = macptr;
/*              title("Calling ARexx Macro ... "); */
            } else {
                Permit();
                title("Unknown Command   -   No Macros:  ARexx Not Active ");   /* no REXX port */
                DeleteRexxMsg(macptr);
                DeleteArgstring(macarg);

                ret = -1;
            }
        } else {
            title("CreateRexxMsg() Failed ");   /* may be overkill, and not need to ckeck this */
            DeleteArgstring(macarg);
            ret = -1;
        }
    } else {
        title("CreateArgstring() Failed ");     /* may be overkill, and not need to check this */
        ret = -1;
    }
    return(ret);
}

int
Process_Rexx()
{
    char errmsg[80];        /* don't build a larger error message */

    int  ret;
    int  err;
    struct RexxMsg *cmdptr;

    while(cmdptr = (struct RexxMsg *)GetMsg(RexxPort)){

        if (IsRexxMsg(cmdptr)) {
            char *arg0 = ARG0((cmdptr));
            short i;
            char *str, *aux, quoted;

            CurRxMac = NULL;
            cmderr = CMD_INITIAL;
            RESULT1(cmdptr) = RESULT2(cmdptr) = 0;
            for (i = 0;i < 10 && arg0[i] > ' ' ; i++ )
                RexBuf[i] = isupper(arg0[i])?tolower(arg0[i]):arg0[i];

            RexBuf[i] = 0;
            if (!strcmp(RexBuf, "getval")) {
                foundcmd = 1;
                ret = 1;
                err = cmderr;
                strncpy(RexBuf, ARG0(cmdptr) + 6, 255),
                RexBuf[255] = 0;
                if (cmdptr->rm_Action & RXFF_RESULT) {
                    str = RexBuf;
                    if (str = breakout(&str, &quoted, &aux))
                        RESULT2(cmdptr) = (long) CreateArgstring(str, strlen(str));
                    if (aux)
                        free(aux);
                }
            }

            else if (!strcmp(RexBuf, "rxblock")) {
                foundcmd = 1;
                ret = 1;
                err = cmderr;
                RxBlock = 1;
            }

            else if (!strcmp(RexBuf, "rxunblock")) {
                foundcmd = 1;
                ret = 1;
                err = cmderr;
                RxBlock = 0;
            }

            else {
                ret = do_command(arg0);
                err = cmderr;
            }

            if (foundcmd) {
                ret = (ret == 1) ? 0 : 5;       /* cmd error:  RC = 5  */
            } else {
                ret = do_rexx(ARG0(cmdptr),RexxHostName);  /* another macro?   */
            }

            if(CurRxMac)
                PushMsg(cmdptr,CurRxMac);
            else {
                RESULT1(cmdptr) = ret;
                ReplyMsg((MSG *)cmdptr);
            }

            foundcmd = 1;
            /* do_command("null");   */  /* a kludge to set "foundcmd" */
        } else {
            if (ret = RESULT1(cmdptr)) {
                if (RESULT2(cmdptr)) {
                    if (RESULT2(cmdptr) == 1) {
                        title("Unknown Command ");
                    } else {
                        sprintf(errmsg, "ARexx Macro Error:  Code = %d  Severity = %d ", RESULT2(cmdptr), ret);
                        title(errmsg);
                    }
                } else {
                    sprintf(errmsg, "User Specified Macro Error:  RC = %d ", ret);
                    title(errmsg);
                }
            } else {
                /*
                * if (err <= TITLE_THRESHHOLD) {
                *     title("OK ");
                * }
                */
            }
            ret = ret + err;
            PopMsg(cmdptr,ret);
        }
    }
    return err;
}

void
PushMsg(source,wait)
struct RexxMsg *source,*wait;
{
    struct MacArray *tmp;
    int i;

    for(tmp = RexxPending;tmp;tmp = tmp->Next){
        for(i=0;i<16;i++)
            if(!tmp->macs[i])
                break;
        if(i!=16)
            break;
    }
    if(!tmp){
        tmp = RexxPending;
        RexxPending = malloc(sizeof(struct MacArray));
        memset(RexxPending,sizeof(struct MacArray),0);
        RexxPending->Next = tmp;
        tmp = RexxPending;
        i = 0;
    }
    tmp->macs[i] = wait;
    tmp->replies[i] = source;
}

void PopMsg(struct RexxMsg *signal,int ret)
{
    struct MacArray *tmp;
    int i;

    for(tmp = RexxPending;tmp;tmp = tmp->Next)
        for(i=0;i<16;i++)
            if(tmp->macs[i] == signal){
                tmp->macs[i] = NULL;                /* could actually try to free MacArray here, but it'll */
                RESULT1(tmp->replies[i]) = ret;     /* eventually free itself (upon exit), so why bother? */
                ReplyMsg((MSG *)tmp->replies[i]);   /* ^^^ assuming malloc tacks mem onto Task->MemList...*/
                return;
            }
}

#endif
