/***************** WARNING ****************
*  DO NOT EDIT THIS FILE DIRECTLY - IT IS *
*  GENERATED AUTOMATICALLY BY THE CONFIG  *
*  PROCESS IN THE 'mframe' SUBDIRECTORY.  *
****************** WARNING ***************/
/* Interface for functions that dissect/make method calls 
   Copyright (C) 1994, 1996, 1998 Free Software Foundation, Inc.
   
   Written by:  Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
   Created: Oct 1994
   
   This file is part of the GNUstep Base Library.

   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., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
   */ 

#ifndef __mframe_h_GNUSTEP_BASE_INCLUDE
#define __mframe_h_GNUSTEP_BASE_INCLUDE

#include <base/preface.h>

#include <base/DistributedObjects.h>

/* For NSArgumentInfo we include NSMethodSignature.h */
#include <Foundation/NSMethodSignature.h>

#if NeXT_runtime
typedef union {
  char *arg_ptr;
  char arg_regs[sizeof (char*)];
} *arglist_t;
#endif

/* These functions are used to pull apart method calls, and put them
   back together again.  They are useful for things like distributed
   objects, and cross-language communication glue between Objective C
   and other languages. */

/* xxx Currently these function only work with the GNU Objective C
   runtime, not the NeXT runtime. */


/* Extract the arguments to a method call, as found in ARGFRAME,
   according to type string TYPES, and encode them by calling ENCODER.
   Return YES if and only if the method has some pass-by-reference
   arguments. */

BOOL
mframe_dissect_call (arglist_t argframe, const char *types,
		     void (*encoder)(DOContext*), DOContext *ctxt);

/* Decode the arguments to a method call by calling DECODER, knowing
   what to decode by looking at type string ENCODED_TYPES.  Build an
   argframe of type arglist_t, and invoke the method.  Then encode the
   return value and the pass-by-reference values using ENCODER. */

void
mframe_do_call (DOContext *ctxt,
		void(*decoder)(DOContext*),
		void(*encoder)(DOContext*));

/* Decode the return value and pass-by-reference arguments using
   DECODER, knowning what to decode by looking at type string TYPES
   and OUT_PARAMETERS, and put then into ARGFRAME.  Return the
   retval_t structure that can be passed to __builtin_return(). */

retval_t 
mframe_build_return (arglist_t argframe, const char *types, 
		     BOOL out_parameters,
		     void(*decoder)(DOContext*), DOContext *ctxt);

/*
 *	Copy the return value from retframe into the specified buffer.
 */
BOOL
mframe_decode_return(const char *type, void* buffer, void* retframe);

/*
 *	Return the value of the specified type in 'retval' using argFrame.
 */
void*
mframe_handle_return(const char* type, void* retval, arglist_t argFrame);

/*
 *	Step through method encoding information extracting details.
 */
const char *
mframe_next_arg(const char *typePtr, NSArgumentInfo *info);

/*
 *	Generate method encoding with stack/register offsets from a simple
 *	type encoding string.  Store results in 'buf' or allocate memory
 *	using objc_malloc() if 'buf' is a nul pointer.
 */
char*
mframe_build_signature(const char *typePtr, int *size, int *narg, char *buf);


arglist_t
mframe_create_argframe(const char *types, void** retbuf);

void
mframe_destroy_argframe(const char *types, arglist_t argframe);

#define ROUND(V, A) \
  ({ typeof(V) __v=(V); typeof(A) __a=(A); \
     __a*((__v+__a-1)/__a); })


int method_types_get_sizeof_arguments (struct objc_method* mth);
char* method_types_get_next_argument (arglist_t argf, const char **type);
char* method_types_get_first_argument (struct objc_method* m,
                           arglist_t argframe,
                           const char** type);


/* See ../README for copyright */

#define	MFRAME_STACK_STRUCT	0
#define	MFRAME_STRUCT_BYREF	0
#define	MFRAME_SMALL_STRUCT	0
#define MFRAME_ARGS_SIZE	8
#define MFRAME_RESULT_SIZE	116

#define MFRAME_GET_STRUCT_ADDR(ARGS, TYPES) \
((*(TYPES)==_C_STRUCT_B || *(TYPES)==_C_UNION_B || *(TYPES)==_C_ARY_B) ? \
      *(void**)((ARGS)->arg_regs + sizeof(void*)) : (void*)0)

#define MFRAME_SET_STRUCT_ADDR(ARGS, TYPES, ADDR) \
({if (*(TYPES)==_C_STRUCT_B || *(TYPES)==_C_UNION_B || *(TYPES)==_C_ARY_B) \
      *(void**)((ARGS)->arg_regs + sizeof(void*)) = (ADDR);})

#define MFRAME_ARGS int

#define MFRAME_INIT_ARGS(CUM, RTYPE)	\
((CUM) = (*(RTYPE)==_C_STRUCT_B || *(RTYPE)==_C_UNION_B || \
    *(RTYPE)==_C_ARY_B) ? sizeof(void*) : 0)

#define MFRAME_ARG_ENCODING(CUM, TYPE, STACK, DEST) \
({  \
  const char* type = (TYPE); \
  int align = objc_alignof_type(type); \
  int size = objc_sizeof_type(type); \
\
  (CUM) = ROUND((CUM), align); \
  (TYPE) = objc_skip_typespec(type); \
  sprintf((DEST), "%.*s%d", (TYPE)-type, type, (CUM)); \
  if (*(TYPE) == '+') (TYPE)++; \
  while (isdigit(*(TYPE))) \
    { \
      (TYPE)++; \
    } \
  (DEST)=&(DEST)[strlen(DEST)]; \
  if ((*type==_C_STRUCT_B||*type==_C_UNION_B||*type==_C_ARY_B)&&size>2) \
    { \
      (STACK) = (CUM) + ROUND(size, align); \
    } \
  else \
    { \
      (STACK) = (CUM) + size; \
    } \
  (CUM) += ROUND(size, sizeof(void*)); \
})


inline static void*
mframe_arg_addr(arglist_t argf, NSArgumentInfo *info)
{
  int	offset = info->offset;
#if WORDS_BIGENDIAN
  if (info->size < sizeof(int))
    {
      offset += sizeof(int) - info->size;
    }
#endif
#if NeXT_RUNTIME
  return marg_getRef(argf, offset, void);
#else
  if (info->isReg)
    {
      return(argf->arg_regs + offset);
    }
  else
    {
      return(argf->arg_ptr + offset);
    }
#endif
}

inline static void
mframe_get_arg(arglist_t argf, NSArgumentInfo *info, void* buffer)
{
#if MFRAME_STRUCT_BYREF || MFRAME_FLT_IN_FRAME_AS_DBL
  const char	*typ = info->type;
#endif
#if MFRAME_STRUCT_BYREF

  /*
   *	If structures are passed in the stack frame by reference - we need
   *	to copy the actual structure, rather than it's pointer.
   */
  if (*typ == _C_STRUCT_B || *typ == _C_UNION_B || *typ == _C_ARY_B)
    {
      memcpy(buffer, *(void**)mframe_arg_addr(argf, info), info->size);
    }
  else
#endif
#if MFRAME_FLT_IN_FRAME_AS_DBL
  if (*typ == _C_FLT)
    {
      *(float*)buffer = (float)*(double*)mframe_arg_addr(argf, info);
    }
  else
#endif
  memcpy(buffer, mframe_arg_addr(argf, info), info->size);
}

inline static void
mframe_set_arg(arglist_t argf, NSArgumentInfo *info, void* buffer)
{
#if MFRAME_STRUCT_BYREF || MFRAME_FLT_IN_FRAME_AS_DBL
  const char	*typ = info->type;
#endif
#if MFRAME_STRUCT_BYREF

  /*
   *	If structures are passed in the stack frame by reference - we need
   *	to copy a pointer onto the stack rather than the actual structure.
   */
  if (*typ == _C_STRUCT_B || *typ == _C_UNION_B || *typ == _C_ARY_B)
    {
      memcpy(mframe_arg_addr(argf, info), &buffer, sizeof(void*));
    }
  else
#endif
#if MFRAME_FLT_IN_FRAME_AS_DBL
  if (*typ == _C_FLT)
    {
      *(double*)mframe_arg_addr(argf, info) = *(float*)buffer;
    }
  else
#endif
  memcpy(mframe_arg_addr(argf, info), buffer, info->size);
}

inline static void
mframe_cpy_arg(arglist_t dst, arglist_t src, NSArgumentInfo *info)
{
#if MFRAME_STRUCT_BYREF
  const char	*typ = info->type;

  /*
   *	If structures are passed in the stack frame by reference - we need
   *	to copy a pointer onto the stack rather than the actual structure.
   */
  if (*typ == _C_STRUCT_B || *typ == _C_UNION_B || *typ == _C_ARY_B)
    {
      memcpy(mframe_arg_addr(dst, info), mframe_arg_addr(src, info), sizeof(void*));
    }
  else
#endif
    memcpy(mframe_arg_addr(dst, info), mframe_arg_addr(src, info), info->size);
}

#endif /* __mframe_h_GNUSTEP_BASE_INCLUDE */
