#ifndef lint
static char *RCSid = "$Id: client.c,v 1.2 1993/05/10 05:57:55 anders Exp anders $";
#endif

/*
 *  The Regina Rexx Interpreter
 *  Copyright (C) 1993-1994  Anders Christensen <anders@pvv.unit.no>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library 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
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, write to the Free
 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "rexx.h"

#include <unistd.h>
#include "rxiface.h"
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <stdarg.h>

extern int isclient ;

static streng *environment=NULL ;

/* #define DEBUG_CLIENT */

int ReMapHook( int NetHook ) ;


static streng *wrapstring( char *string, int length ) 
{
   streng *result ;

   if (length>=0 && string)
   {
      result = Str_make( length ) ;
      memcpy( result->value, string, length ) ;
      result->len = length ;
   }
   else 
      result = NULL ;

   return result ;
}


int map_type( int in ) 
{
   if (in==RX_TYPE_COMMAND)
      return INVO_COMMAND ;
   else if (in==RX_TYPE_FUNCTION)
      return INVO_FUNCTION ;
   else
   {
      assert( in == RX_TYPE_SUBROUTINE ) ;
      return INVO_SUBROUTINE ;
   }
}


void closedown( void )
{
   exit( 0 ) ;
}

int IfcStartUp( char *name, int *Major, int *Minor ) 
{
   static char *args[] = { "regina", "-Ci,foo", NULL } ;
   int dummy_main( int argc, char *argv[] ) ;
   int rc ;

   rc = dummy_main( 2, args ) ;

   *Major = RXVERSION_MAJ ;
   *Minor = RXVERSION_MIN ;
   return rc ;
}


paramboxptr parametrize( int ArgCount, int *ParLengths, char *ParStrings[] ) 
{
   paramboxptr parms, root ;
   int count, i ;

   root = parms = NULL ;

   count = ArgCount ;
   for (i=0; count--; i++ ) 
   {
      if (parms)
      {
         parms->next = Malloc( sizeof(parambox)) ;
         parms = parms->next ;
      }
      else
         parms = root = Malloc( sizeof(parambox )) ;

      parms->value = wrapstring( ParStrings[i], ParLengths[i] ) ; 
   }

   if (parms)
      parms->next = NULL ;

   return root ;
}



int IfcExecScript( int NameLen, char *Name, 
                   int ArgCount, int *ParLengths, char *ParStrings[],
                   int CallType, int ExitFlags, int EnvLen, char *EnvName,
                   int WhereCode, char *WherePtr, int WhereLen, 
                   int *RetLen, char **RetString )
{
   streng *command, *result ;
   int RetCode ;
   int hooks, num, ctype ;
   int type=0 ;
   paramboxptr params ;

   command = wrapstring( Name, NameLen ) ;
   assert(command) ;
   params = parametrize( ArgCount, ParLengths, ParStrings ) ;

   ctype = map_type(CallType) ;

   for (hooks=num=0; num<30; num++)
      if ((ExitFlags>>num) & 0x01)
         hooks |= (1 << (ReMapHook(num))) ;
 
   environment = wrapstring( EnvName, EnvLen ) ; 
   if (!environment)
      environment = Str_cre( "DEFAULT" ) ;
   
   add_envir( Str_dup(environment), ENVIR_PIPE, 0 ) ;

   type = WhereCode ;
   if (type==RX_TYPE_EXTERNAL)
      result=execute_external(command,params,environment,&RetCode,hooks,
                              ctype);
   else if (type==RX_TYPE_INSTORE)
   {
      streng *sptr = wrapstring( WherePtr, WhereLen ) ;
      int serial = atopos( sptr ) ;
      Free( sptr ) ;
      result=do_instore(command,params,environment,&RetCode,hooks,type,
                              serial, ctype);
   }
   else if (type==RX_TYPE_MACRO)
      result= nullstringptr() ;
   else if (type==RX_TYPE_SOURCE)
   {
      streng *SrcStr = wrapstring( WherePtr, WhereLen ) ;
      int serial ;
      serial=enter_macro( SrcStr, command ) ;
      Free_string( SrcStr ) ;
/*
 *    SendNumber( RX_INSTORE ) ;
 *    SendNumber( serial ) ;
 */
      result=do_instore(command,params,environment,&RetCode,hooks,type,
                              serial,ctype);
   }
   else
   {
      exiterror( ERR_INTERPRETER_FAILURE ) ;
      return 0 ;
   }
   
   del_envir( environment ) ;
   Free_string( environment ) ;

   if (result)
   {
      *RetLen = result->len ;
      *RetString = result->value ;
   }
   else
      *RetLen = RX_NO_STRING ;
   
   return RetCode ;
}


static int handle_source( int *Length, char **String )
{
   int infile, called, total, invoked ;
   char *stype, *ctmp ;
   int sleng ;
   extern sysinfo systeminfo ;

   stype = system_type() ;
   sleng = strlen( stype ) ;
   infile = systeminfo->input_file->len ;
   called = systeminfo->called_as->len ;
   invoked = strlen(invo_strings[systeminfo->invoked]) ;
   total = sleng + 1 + invoked + 1 + infile + 1 + called ;

   ctmp = *String = Malloc( (*Length=total)+2 ) ;
   sprintf( ctmp, "%s %s ", stype, invo_strings[systeminfo->invoked]) ;
   strncat( ctmp, systeminfo->called_as->value, called ) ;
   strcat( ctmp, " " ) ;
   strncat( ctmp, systeminfo->input_file->value, called ) ;

   return RX_CODE_OK ;
}

static int handle_param( int *Length, char **String ) 
{
   extern proclevel currlevel ;
   paramboxptr ptr ;
   streng *value ;
   int number ;

   ptr = currlevel->args ;
   value = wrapstring( *String, *Length ) ;
   number = atopos( value ) ;
   Free_string( value ) ;
   value = get_parameter( ptr, number ) ;

   if (value)
   {
      *(Length+1) = value->len ;
      *(String+1) = value->value ;
   }
   else
      *(Length+1) = RX_NO_STRING ;

   return RX_CODE_OK ;
}


void SetupClient( char *ptr ) {} 
void SetupInternal( char *ptr ) { isclient=2 ; }


static int handle_no_of_params( int *Length, char **String ) 
{
   extern proclevel currlevel ;
   paramboxptr ptr ;
   static char scratch[32] ;
   int count=0 ;

   ptr = currlevel->args ;
   count = count_params( ptr, PARAM_TYPE_HARD ) ;

   sprintf( *String=scratch, "%d", count ) ;
   *Length = strlen(*String) ;

   return RX_CODE_OK ;
}



static int var_indicator=0 ;
static int get_next_var( int *Lengths, char **Strings )
{
   variableptr value, rval, rrval ;

   if (var_indicator==0)
   {
      get_next_variable( 1 ) ;
      var_indicator = 1 ;
   }

   for (;;)
   {
      value = get_next_variable( 0 ) ;
      for (rval=value; rval && rval->realbox; rval=rval->realbox) ;
      if (rval && !(rval->flag & VFLAG_STR))
      {
         if (rval->flag & VFLAG_NUM)
         {
            expand_to_str( rval ) ;
            break ;
         }

         if (!rval->stem)
            continue ;

         for (rrval=rval->stem; rrval && rrval->realbox; rrval=rrval->realbox);
         if (rrval && !(rrval->flag & VFLAG_STR))
            if (rval->flag & VFLAG_NUM)
            {
               expand_to_str( rval );
               break ;
            }
            else
               continue ;
      }
      break ;
   }

   if (rval)
   {
      if (rval->stem)
      {
         Lengths[0] = rval->stem->name->len + rval->name->len ;
         Strings[0] = Malloc( Lengths[0] ) ;
         memcpy(Strings[0], rval->stem->name->value, rval->stem->name->len);
         memcpy(Strings[0]+rval->stem->name->len, 
                                      rval->name->value, rval->name->len ) ;
      }
      else
      {
         Lengths[0] = rval->name->len ;
         Strings[0] = rval->name->value ;
      }

      if (rval->value)
      {
         Lengths[1] = rval->value->len ;
         Strings[1] = rval->value->value ;
      }
      else
      {
         assert( rval->stem && rrval->value ) ;
         Lengths[1] = rval->stem->name->len + rval->name->len ; 
         Strings[1] = Malloc( Lengths[1] ) ;
         memcpy( Strings[1], rval->stem->name->value, value->stem->name->len );
         memcpy( Strings[1]+value->stem->name->len, 
                                        rval->name->value, rval->name->len ) ;
      }

      return 2 ;
   }
   else
      return 0 ;
}



void RunClient( void ) 
{
/*
   int code ;

   while (1)
   {
      code = ReadNumber() ;
      if (code==RX_EXECUTE)
         execute_an_external() ;
      else if (code==RX_DROP_INSTORE)
      {
         kill_macro( NULL, ReadNumber()) ;
         SendNumber( RX_RETVOID ) ;
      }
      else 
         exiterror( ERR_INTERPRETER_FAILURE ) ;

   }
 */

/*
   Free_string( WaitForReturn( &rc ) ) ;
 */
}


int MapHook( int RexxHook ) 
{
   switch ( RexxHook ) 
   {
      case HOOK_STDOUT: return RX_EXIT_STDOUT ;
      case HOOK_STDERR: return RX_EXIT_STDERR ;
      case HOOK_TRCIN:  return RX_EXIT_TRCIN ;
      case HOOK_PULL:   return RX_EXIT_PULL ;

      case HOOK_INIT:   return RX_EXIT_INIT ;
      case HOOK_TERMIN: return RX_EXIT_TERMIN ;

      default: 
         closedown() ;
   }

   return 0 ;
}
         

int ReMapHook( int NetHook ) 
{
   switch ( NetHook ) 
   {
      case RX_EXIT_STDOUT: return HOOK_STDOUT ;
      case RX_EXIT_STDERR: return HOOK_STDERR ;
      case RX_EXIT_TRCIN:  return HOOK_TRCIN ;
      case RX_EXIT_PULL:   return HOOK_PULL ;

      case RX_EXIT_TERMIN: return HOOK_TERMIN ;
      case RX_EXIT_INIT:   return HOOK_INIT ;

      default: 
         closedown() ;
   }

   return 0 ;
}
         


int hookup( int hook, ... )
{
   int rcode, code ;
   va_list ap ;
   char *nullptr=NULL ;
   char *RetString ;
   int RetLength ;
   streng *indata, **outdata ;

   va_start( ap, hook ) ;

#ifdef lint 
   outdata = NULL ;
   rcode = 0 ;
#endif
   switch ( code=MapHook(hook))
   {
      case RX_EXIT_STDOUT:
      case RX_EXIT_STDERR:
         indata = va_arg(ap, streng*) ;
         if (indata)
         {
            RetLength = indata->len ;
            RetString = indata->value ;
            rcode = IfcDoExit( code, &RetLength, &RetString ) ;
         }
         else
         {
            RetLength = RX_NO_STRING ;
            rcode = IfcDoExit( code, &RetLength, &nullptr ) ;
         }
         break ;

      case RX_EXIT_PULL:
      case RX_EXIT_TRCIN:
         outdata = va_arg(ap, streng**) ;
         rcode = IfcDoExit( code, &RetLength, &RetString ) ;
         break ;

      case RX_EXIT_INIT:
      case RX_EXIT_TERMIN:
         rcode = IfcDoExit( code, NULL, NULL ) ;
         break ;

      default:
         exiterror( ERR_INTERPRETER_FAILURE ) ;
   }
   va_end( ap ) ;

   if (rcode==RX_HOOK_ERROR)
      exiterror( ERR_SYSTEM_FAILURE ) ;
   else if (rcode==RX_HOOK_GO_ON)
      rcode = HOOK_GO_ON ;
   else if (rcode==RX_HOOK_NOPE)
      rcode = HOOK_NOPE ;
   else
      exiterror( ERR_INTERPRETER_FAILURE ) ;

   switch ( MapHook(hook))
   {
      case RX_EXIT_PULL:
      case RX_EXIT_TRCIN:
         (*outdata) = wrapstring( RetString, RetLength ) ;
         if (!*outdata)
            *outdata = Str_cre("") ;
         break ;

      case RX_EXIT_STDOUT:
      case RX_EXIT_STDERR:
      case RX_EXIT_INIT:
      case RX_EXIT_TERMIN:
         break ;

      default:
         exiterror( ERR_INTERPRETER_FAILURE ) ;
   }

   return rcode ;
}



streng *SubCom( streng *command, streng *envir, int *rc ) 
{
   int tmplen ;
   char *tmpptr ;

   *rc = IfcSubCmd( (envir ? envir->len : RX_NO_STRING), 
                    (envir ? envir->value : NULL), 
                     command->len, command->value, &tmplen, &tmpptr ) ;   

   return wrapstring( tmpptr, tmplen ) ;
}





int GetSymVariable( int *Lengths, char *Strings[] ) 
{
   streng *varbl, *value ;
   int rcode ;

   varbl = wrapstring( Strings[0], Lengths[0] ) ;
   assert( varbl ) ;

   rcode = RX_CODE_OK ;
   if (!valid_var_symbol(varbl))
   {
      rcode = RX_CODE_INVNAME ;
      Lengths[1] = RX_NO_STRING ;
   }
   else
   {
      value = getvalue( varbl, 1 ) ;
      if (!var_was_found())
      {
         value = Str_dup(value) ;
         rcode = RX_CODE_NOVALUE ;
      }
      Lengths[1] = value->len ;
      Strings[1] = value->value ;
   }

   Free_string( varbl ) ;
   return rcode ;
}

int SetSymVariable( int *Lengths, char *Strings[] ) 
{
   streng *varbl, *value ;
   int rcode ;

   varbl = wrapstring( Strings[0], Lengths[0] ) ;
   value = wrapstring( Strings[1], Lengths[1] ) ;
   assert( varbl ) ;

   rcode = RX_CODE_OK ;
   if (!valid_var_symbol(varbl))
   {
      rcode = RX_CODE_INVNAME ;
   }
   else
   {
      if (value)
         setvalue( varbl, value ) ;
      else
         drop_var( varbl ) ;

      if (!var_was_found())
         rcode = RX_CODE_NOVALUE ;
   }

   Free_string( varbl ) ;
   return rcode ;
}

static int handle_version( int *Length, char **String ) 
{
   *Length = strlen(PARSE_VERSION_STRING) ;
   *String = PARSE_VERSION_STRING ;
   return RX_CODE_OK ;
}


static int handle_queue( int *Length, char **String )
{
   *Length = 7 ;
   *String = "default" ;
   return RX_CODE_OK ;
}




int IfcVarPool( int Code, int *Lengths, char *Strings[] ) 
{
   int rc ;

   if (Code==RX_GETSVAR)
      rc = GetSymVariable( Lengths, Strings ) ;
   else if (Code==RX_SETSVAR)
      rc = SetSymVariable( Lengths, Strings ) ;
   else if (Code==RX_NEXTVAR)
      rc = get_next_var( Lengths, Strings ) ;
   else if (Code==RX_CODE_VERSION)
      rc = handle_version( Lengths, Strings ) ;
   else if (Code==RX_CODE_SOURCE)
      rc = handle_source( Lengths, Strings ) ;
   else if (Code==RX_CODE_QUEUE)
      rc = handle_queue( Lengths, Strings ) ;
   else if (Code==RX_CODE_PARAMS)
      rc = handle_no_of_params( Lengths, Strings ) ;
   else if (Code==RX_CODE_PARAM)
      rc = handle_param( Lengths, Strings ) ;
   else
      assert( 0 ) ;

   return rc ;
}




int IfcRegFunc( char *Name )
{
   assert( Name ) ;
   addfunc( Str_cre( Name ), 1 ) ;
   return RX_CODE_OK ;
}


int IfcDelFunc( char *Name ) 
{ 
   assert( Name ) ;
   delfunc( Str_cre( Name )) ;
   return RX_CODE_OK ;
}


streng *do_an_external( streng *name, paramboxptr parms )
{
   static char *namespc=NULL ;
   static int namelen=(-1) ;
   static int *Lengths=NULL ;
   static int strlen=(-1) ;
   static char **Strings=NULL ;
   int RetLength ;
   char *RetString ;
   streng *retval ;
   int rc ;
   int RC ;
   int i, j ;
   paramboxptr p ;

   if (name->len>=namelen)
   {
      if (namespc)
         Free( namespc ) ;

      namespc = Malloc( name->len + 1 ) ;
   }
   memcpy( namespc, name->value, name->len ) ;
   namespc[name->len] = 0x00 ;

   for (j=i=0,p=parms; p; p=p->next,i++) 
      if (p->value)
         j=i+1 ;

   if (j>strlen)
   {
      if (Lengths)
         Free( Lengths ) ;

      if (Strings) 
         Free( Strings ) ;

      Lengths = Malloc( sizeof(int)*j ) ;
      Strings = Malloc( sizeof(char*)*j ) ;
      strlen = j ;
   }

   for (i=0,p=parms; p && i<=j; p=p->next,i++)
      if (p->value)
      {
         Lengths[i] = p->value->len ; 
         Strings[i] = p->value->value ;
      }
      else
         Lengths[i] = RX_NO_STRING ;

   rc = IfcExecFunc( namespc, j, Lengths, Strings, 
                     &RetLength, &RetString, &RC );

   if (rc)
   {
      exiterror( ERR_INCORRECT_CALL ) ;
      retval = NULL ;
   }
   else
   {
      retval = Str_make( RetLength ) ;
      memcpy( retval->value, RetString, RetLength ) ;
      retval->len = RetLength ;
   }
   return retval ;
}

