/* ARexx.c - Amiga specific rexx interface routines                     */
/* A simple ARexx interface from AmigaMail XIV pp.23-40 by Michael Sinz */
/* Additions to XLISP-STAT 2.1 Copyright (c) 1990, by Luke Tierney      */
/* Additions to Xlisp 2.1, Copyright (c) 1989 by David Michael Betz     */
/* You may give out copies of this software; for conditions see the     */
/* file COPYING included with this distribution.                        */


#include <proto/exec.h>
#include <exec/memory.h>
#include <string.h>
#include <ctype.h>
#define extern
#include <rexx/rexx.h>
#undef extern
#include <rexx/simplerexx.h>

char *ARexxName(AREXXCONTEXT RexxContext){
   register char *tmp=NULL;
   if(RexxContext)tmp=RexxContext->PortName;
   return(tmp);}

ULONG ARexxSignal(AREXXCONTEXT RexxContext){
   register ULONG tmp=NULL;
   if(RexxContext)tmp=1L<<RexxContext->ARexxPort->mp_SigBit;
   return(tmp);}

struct RexxMsg *GetARexxMsg(AREXXCONTEXT RexxContext){
   register struct RexxMsg *tmp=NULL;
   register short flag;
   if(RexxContext&&(tmp=(struct RexxMsg *)GetMsg(RexxContext->ARexxPort))){
      if(tmp->rm_Node.mn_Node.ln_Type==NT_REPLYMSG){
         flag=FALSE;
         if(tmp->rm_Result1)flag=TRUE;
         DeleteArgstring(tmp->rm_Args[0]);
         DeleteRexxMsg(tmp);
         RexxContext->Outstanding-=1;
         tmp=flag?REXX_RETURN_ERROR:NULL;}}
   return(tmp);}

void ReplyARexxMsg(AREXXCONTEXT RexxContext, struct RexxMsg *rmsg,char *RString,
LONG Error){
   if(RexxContext&&rmsg&&rmsg!=REXX_RETURN_ERROR){
      rmsg->rm_Result2=0;
      if(!(rmsg->rm_Result1=Error)){
         if((rmsg->rm_Action&(1L<<RXFB_RESULT))&&RString){
            rmsg->rm_Result2=(LONG)CreateArgstring(RString,(LONG)strlen(RString));}}
      ReplyMsg((struct Message *)rmsg);}}

short SetARexxLastError(AREXXCONTEXT RexxContext,struct RexxMsg *rmsg,char *ErrorString){
   register short OkFlag=FALSE;
   if(RexxContext&&rmsg&&CheckRexxMsg(rmsg)){
      if(!SetRexxVar(rmsg,RexxContext->ErrorName,ErrorString,(long)strlen(ErrorString))){
         OkFlag=TRUE;}}
   return(OkFlag);}

short SendARexxMsg(AREXXCONTEXT RexxContext,char *RString,short StringFile){
   register struct MsgPort *RexxPort;
   register struct RexxMsg *rmsg;
   register short flag=FALSE;
   if(RexxContext&&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))){
            Forbid();
            if(RexxPort=FindPort(RXSDIR)){
               PutMsg(RexxPort,(struct Message *)rmsg);
               RexxContext->Outstanding+=1;;
               flag=TRUE;}
            else {
               DeleteArgstring(rmsg->rm_Args[0]);
               DeleteRexxMsg(rmsg);}
            Permit();}
         else DeleteRexxMsg(rmsg);}}
   return(flag);}

void FreeARexx(AREXXCONTEXT RexxContext){
   register struct RexxMsg *rmsg;
   if(RexxContext){
      RexxContext->PortName[0]='\0';
      while(RexxContext->Outstanding){
         WaitPort(RexxContext->ARexxPort);
         while(rmsg=GetARexxMsg(RexxContext)){
            if(rmsg!=REXX_RETURN_ERROR){
               SetARexxLastError(RexxContext,rmsg,"99: Port Closed!");
               ReplyARexxMsg(RexxContext,rmsg,NULL,100);}}}
      if(RexxContext->ARexxPort){
         while(rmsg=GetARexxMsg(RexxContext)){
            SetARexxLastError(RexxContext,rmsg,"99: Port Closed!");
            ReplyARexxMsg(RexxContext,rmsg,NULL,100);}
         DeletePort(RexxContext->ARexxPort);}
      if(RexxContext->RexxSysBase)CloseLibrary(RexxContext->RexxSysBase);
      FreeMem(RexxContext,sizeof(struct ARexxContext));}}

AREXXCONTEXT InitARexx(char *AppName,char *Extension){
   register AREXXCONTEXT RexxContext;
   register short loop,count;
   register char *tmp;
   if(RexxContext=AllocMem(sizeof(struct ARexxContext),MEMF_PUBLIC|MEMF_CLEAR)){
      if(RexxContext->RexxSysBase=OpenLibrary("rexxsyslib.library",NULL)){
         if(!Extension)Extension="rexx";
         tmp=RexxContext->Extension;
         for(loop=0;(loop<7)&&(Extension[loop]);loop++){
            *tmp++=Extension[loop];}
         *tmp='\0';
         tmp=RexxContext->PortName;
         for(loop=0;(loop<16)&&(AppName[loop]);loop++){
            *tmp++=toupper(AppName[loop]);}
         *tmp='\0';
         strcpy(RexxContext->ErrorName,RexxContext->PortName);
         strcat(RexxContext->ErrorName,".LASTERROR");
         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);}
