/* arexx.c - handling of the arexx interface to the handler.
   Copyright (C) 1991, 1992, 1993 Kristian Nielsen.

   This file is part of XFH, the compressing file system handler.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            */

/* Some of this code is taken from the 'fancydemo.c' AREXX example.
 *
 * NOTE: There's no code to facilitate returning result strings yet.
 * Some code is commented out, and there is no lib open.
 */

#include "CFS.h"

#include <rexx/storage.h>
#include <rexx/rxslib.h>
#include <exec/ports.h>

#include <ctype.h>
#include <string.h>

#include "dossupport.h"

#ifdef GIVE_AREXX_RESULT_STRINGS
/* THIS NAME MUST BE RexxSysBase FOR THE GLUE ROUTINES */
struct RxsLib *RexxSysBase = NULL;   /* this is the rexx library base */
#endif

/* Replies a REXX message, filling in the appropriate codes.  If the macro
 * program has requested a result string, the return argstring is allocated
 * and installed in the rm_Result2 slot.
 *
 * A result is returned ONLY IF REQUESTED AND THE PRIMARY RESULT == 0.
 */

static void reply_rexx_command(struct RexxMsg *rexxmessage,
                            LONG primary,LONG secondary,char *result){
   /* set an error code */
   if (primary == 0 && (rexxmessage->rm_Action & 1L<<RXFB_RESULT)){
#ifdef GIVE_AREXX_RESULT_STRINGS
      secondary = result ? (long) CreateArgstring(result,strlen(result))
                         : (long) NULL;
#else
      if(result) debug(("***PANIC: Internal / attempt to return AREXX result string.\n"));
      secondary = (long) NULL;
#endif
   }
   rexxmessage->rm_Result1 = primary;
   rexxmessage->rm_Result2 = secondary;
   ReplyMsg(&rexxmessage->rm_Node);
}


#define SETOPTION_CMD "SETOPTION"

static void execute_command(glb glob, struct RexxMsg *msg){
   LONG primary, secondary = 0L;
   char *p,*q,*r;
   
   debug(("AREXX command received: \"%s\".\n",msg->rm_Args[0]));

   /* ToDo: Have some real command parsing. This bit test for just a
    * single command: SETOPTION.
    */
   p = msg->rm_Args[0];
   while(*p && isspace(*p)) p++;  /* Skip white space. */
   q=p;
   while(*p && !isspace(*p)) p++; /* Find end of cmd name. */
   r=p;
   while(*p && isspace(*p)) p++;  /* Skip white space. */
   
   /* At this point, q points to command, r to command end, p to args. */
   if(r-q==strlen(SETOPTION_CMD) && !strnicmp(q,SETOPTION_CMD,r-q)){
      primary = set_option(glob,p) ? 0L : 10L;
   }else{
      /* Unrecognised command. */
      primary = 10L;   /* Return error. */
   }

   reply_rexx_command(msg,primary,secondary,NULL);
}


void checkarexxmsg(glb glob){
   struct RexxMsg *msg;   /* incoming rexx messages */

  /* did we get something from rexx? */
  while(msg = (struct RexxMsg *)GetMsg(glob->arexxport)){
      /* a rexx macro has sent us a command, deal with it */
      /* THE MESSAGE WILL HAVE BEEN REPLIED INSIDE OF execute_command */
      execute_command(glob, msg);
  }
}


ULONG arexxsigmask(glb glob){
   return (ULONG)1 << glob->arexxport->mp_SigBit;
}


BOOL InitArexx(glb glob){
  struct MsgPort *port;
  char *portname;
  
  if(!glob->userarexxportname){
    /* Find a suitable name for the port. */
    if(!(portname=dosalloc(AREXXPORTMAXLEN+strlen(glob->devname)))){
      debug(("Error: InitArexx(): No memory for port name.\n"));
      OUTOFMEM;
      return FALSE;
    }
    SPrintF(portname,AREXXPORTTEMPLATE,glob->devname);
  }else{
    if(!(portname=dosalloc(1+strlen(glob->userarexxportname)))){
      debug(("Error: InitArexx(): No memory for port name.\n"));
      OUTOFMEM;
      return FALSE;
    }
    strcpy(portname, glob->userarexxportname);
  }  
  Forbid();
  /* look for someone else that looks just like us! */
  if (FindPort(portname)){
    Permit();
    debug(("A public port called '%s' already exists!\n",portname));
    dosfree(portname);
    glob->ioerr = ERROR_OBJECT_EXISTS;
    return FALSE;
  }
  
  /* allocate the port */
  if(!(port = CreatePort(portname,AREXXPORTPRI))){
    debug(("Error: InitArexx(): Unable to CreatePort().\n"));
    dosfree(portname);
    OUTOFMEM;
    return FALSE;
  }
  Permit();
  
  glob->arexxportname = portname;
  glob->arexxport = port;
  return TRUE;
}

void CleanupArexx(glb glob){

   debug(("Cleaning up Arexx resources..."));   
   if(glob->arexxport){
      struct RexxMsg *msg;
      
      /* Careful: reply any pending messages. */
      Forbid();
      while(msg=(struct RexxMsg *)GetMsg(glob->arexxport)){
         reply_rexx_command(msg,20,0,NULL);
      }
      DeletePort(glob->arexxport);
      Permit();
      glob->arexxport = NULL;
   }
   if(glob->arexxportname) dosfree(glob->arexxportname);
   debug(("all cleaned up.\n"));
}

/* End of arexx.c */
