ftp.nice.ch/Attic/openStep/implementation/gnustep/sources/libobjects-0.1.19.tgz#/libobjects-0.1.19/src/Invocation.m

This is Invocation.m in view mode; [Download] [Up]

/* Implementation for Objective-C Invocation object
   Copyright (C) 1993,1994, 1995, 1996 Free Software Foundation, Inc.

   Written by:  R. Andrew McCallum <mccallum@gnu.ai.mit.edu>
   Date: May 1993

   This file is part of the GNU Objective C Class 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ 

#include <objects/Invocation.h>

/* Deal with strrchr: */
#if STDC_HEADERS || HAVE_STRING_H
#include <string.h>
/* An ANSI string.h and pre-ANSI memory.h might conflict.  */
#if !STDC_HEADERS && HAVE_MEMORY_H
#include <memory.h>
#endif /* not STDC_HEADERS and HAVE_MEMORY_H */
#define rindex strrchr
#define bcopy(s, d, n) memcpy ((d), (s), (n))
#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n))
#define bzero(s, n) memset ((s), 0, (n))
#else /* not STDC_HEADERS and not HAVE_STRING_H */
#include <strings.h>
/* memory.h and strings.h conflict on some systems.  */
#endif /* not STDC_HEADERS and not HAVE_STRING_H */


/* 
   Put something like this in Collecting:
   - withObjectsAtArgumentIndex: (unsigned)index
       invoke: (Invocation*)invocation;
   - putObjectsAtArgumentIndex: (unsigned)index
       andInvoke: (Invocation*)invocation;
   - invoke: (Invocation*)invocation
       withObjectsAtArgumentIndex: (unsigned)index
*/

@implementation Invocation

- initWithReturnType: (const char *)enc
{
  int l = strlen(enc);
  OBJC_MALLOC(encoding, char, l);
  memcpy(encoding, enc, l);
  return_size = objc_sizeof_type(encoding);
  return_value = NULL;
  return self;
}
- (void) invoke
{
  [self subclassResponsibility:_cmd];
}

- (void) invokeWithObject: anObj
{
  [self invoke];
}

- (void) invokeWithElement: (elt)anElt
{
  [self invoke];
}

- (const char *) returnType
{
  return encoding;
}

- (unsigned) returnSize
{
  return return_size;
}

- (void) getReturnValue: (void *)addr
{
  memcpy(addr, return_value, return_size);
}

- (void) dealloc
{
  OBJC_FREE(encoding);
  [super dealloc];
}

@end

#if 0
@implementation CurriedInvocation

@end
#endif

static int
types_get_size_of_stack_arguments(const char *types)
{
  const char* type = objc_skip_typespec (types);
  return atoi(type);
}

static int
types_get_size_of_register_arguments(const char *types)
{
  const char* type = strrchr(types, '+');
  if (type)
    return atoi(++type) + sizeof(void*);
  else
    return 0;
}

/* To fix temporary bug in method_get_next_argument() on m68k */
static char*
my_method_get_next_argument (arglist_t argframe,
			          const char **type)
{
  const char *t = objc_skip_argspec (*type);

  if (*t == '\0')
    return 0;

  *type = t;
  t = objc_skip_typespec (t);

  if (*t == '+')
    return argframe->arg_regs + atoi(++t);
  else
    /* xxx What's going on here?  This -8 needed on my 68k NeXT box. */
#if m68k
    return argframe->arg_ptr + (atoi(t) - 8);
#else
    return argframe->arg_ptr + atoi(t);
#endif
}

@implementation ArgframeInvocation

/* This is the designated initializer. */
- initWithArgframe: (arglist_t)frame type: (const char *)type
{
  int stack_argsize, reg_argsize;

  /* xxx we could just use the return part.  Does this matter? */
  [super initWithReturnType:type];

  /* allocate the argframe */
  stack_argsize = types_get_size_of_stack_arguments(type);
  reg_argsize = types_get_size_of_register_arguments(type);
  argframe = (arglist_t) (*objc_malloc)(sizeof(char*) + reg_argsize);
  if (stack_argsize)
    argframe->arg_ptr = (*objc_malloc)(stack_argsize);
  else
    argframe->arg_ptr = 0;

  /* copy the frame into the argframe */
  if (frame)
    {
      memcpy((char*)argframe + sizeof(char*), 
	     (char*)frame + sizeof(char*),
	     reg_argsize);
      memcpy(argframe->arg_ptr, frame->arg_ptr, stack_argsize);
    }

  return self;
}

- initWithType: (const char *)e
{
  [self initWithArgframe:NULL type:e];
  return self;
}

- (const char *) argumentTypeAtIndex: (unsigned)i
{
  const char *tmptype = encoding;

  do 
    {
      tmptype = objc_skip_argspec(objc_skip_typespec(tmptype));
    }
  while (i--);
  return tmptype;
}

- (unsigned) argumentSizeAtIndex: (unsigned)i
{
  return objc_sizeof_type([self argumentTypeAtIndex:i]);
}

- (void) getArgument: (void*)addr atIndex: (unsigned)i
{
  const char *tmptype = encoding;
  void *datum;

  do
    datum = my_method_get_next_argument(argframe, &tmptype);
  while (i--);
  memcpy(addr, datum, objc_sizeof_type(tmptype));
}

- (void) setArgumentAtIndex: (unsigned)i 
    toValueAt: (const void*)addr
{
  const char *tmptype = encoding;
  void *datum;

  do
    datum = my_method_get_next_argument(argframe, &tmptype);
  while (i--);
  memcpy(datum, addr, objc_sizeof_type(tmptype));
}

@end

@implementation MethodInvocation

- initWithArgframe: (arglist_t)frame selector: (SEL)sel
{
  [self initWithArgframe:frame type:sel_get_type(sel)];
  return self;
}

- initWithSelector: (SEL)s
{
  [self initWithArgframe:NULL selector:s];
  return self;
}

- initWithSelector: (SEL)s arguments: receiver, ...
{
  [self initWithSelector:s];
  [self notImplemented:_cmd];
  return self;
}


- (void) invoke
{
  void *ret;
  IMP imp;

  imp = get_imp([self target], [self selector]);
  assert(imp);
  ret = __builtin_apply((void(*)(void))imp,
			argframe, 
			types_get_size_of_stack_arguments(encoding));
  if (*encoding == 'd')
    memcpy(return_value, (char*)ret + 2*sizeof(void*), return_size);
  else
    memcpy(return_value, ret, return_size);
}

- (void) invokeWithTarget: t
{
  [self setArgumentAtIndex:0 toValueAt:&t];
  [self invoke];
}

- (SEL) selector
{
  SEL s;
  [self getArgument:&s atIndex:1];
  return s;
}

- (void) setSelector: (SEL)s
{
  [self setArgumentAtIndex:1 toValueAt:&s];
  if (sel_types_match(sel_get_type([self selector]), sel_get_type(s)))
    [self setArgumentAtIndex:1 toValueAt:&s];
  else
    {
      [self notImplemented:_cmd];
      /* We will need to reallocate the argframe */
    }
}

- target
{
  id t;
  [self getArgument:&t atIndex:1];
  return t;
}

- (void) setTarget: t
{
  [self setArgumentAtIndex:0 toValueAt:&t];
}

@end


/* Many other kinds of Invocations are possible:
   SchemeInvocation, TclInvocation */

#if 0
What is this nonsense?
@interface StreamInvocation
@interface LogInvocation
@interface PrintingInvocation
{
  Stream *stream;
  char *format_string;
}
@end
#endif

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.