mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-30 00:11:26 +00:00
Initial revision
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@97 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
e3f26e6e85
commit
a67179cd36
3 changed files with 449 additions and 0 deletions
82
Headers/gnustep/base/Invocation.h
Normal file
82
Headers/gnustep/base/Invocation.h
Normal file
|
@ -0,0 +1,82 @@
|
|||
#ifndef __Invocation_h_OBJECTS_INCLUDE
|
||||
#define __Invocation_h_OBJECTS_INCLUDE
|
||||
|
||||
/*
|
||||
Use these for notifications!
|
||||
Don't forget to make these archivable / transportable.
|
||||
WARNING: All the (char*) type arguments and return values may
|
||||
extraneous stuff after the first type.
|
||||
*/
|
||||
|
||||
#include <objects/stdobjects.h>
|
||||
#include <objects/Collection.h>
|
||||
|
||||
@interface Invocation : NSObject
|
||||
{
|
||||
char *encoding;
|
||||
unsigned return_size;
|
||||
void *return_value;
|
||||
}
|
||||
- initWithReturnType: (const char *)encoding;
|
||||
- (void) invoke;
|
||||
- (void) invokeWithObject: anObj;
|
||||
- (void) invokeWithElement: (elt)anElt;
|
||||
- (const char *) returnType;
|
||||
- (unsigned) returnSize;
|
||||
- (void) getReturnValue: (void *)addr;
|
||||
@end
|
||||
|
||||
@interface ArgframeInvocation : Invocation
|
||||
{
|
||||
arglist_t argframe;
|
||||
/* char *function_encoding; Using return_encoding */
|
||||
}
|
||||
- initWithArgframe: (arglist_t)frame type: (const char *)e;
|
||||
- initWithType: (const char *)e;
|
||||
- (const char *) argumentTypeAtIndex: (unsigned)i;
|
||||
- (unsigned) argumentSizeAtIndex: (unsigned)i;
|
||||
- (void) getArgument: (void*)addr atIndex: (unsigned)i;
|
||||
- (void) setArgumentAtIndex: (unsigned)i
|
||||
toValueAt: (const void*)addr;
|
||||
@end
|
||||
|
||||
@interface MethodInvocation : ArgframeInvocation
|
||||
- initWithArgframe: (arglist_t)frame selector: (SEL)s;
|
||||
- initWithSelector: (SEL)s;
|
||||
- (void) invokeWithTarget: t;
|
||||
- (SEL) selector;
|
||||
- (void) setSelector: (SEL)s;
|
||||
- target;
|
||||
- (void) setTarget: t;
|
||||
@end
|
||||
|
||||
@interface FunctionInvocation : ArgframeInvocation
|
||||
{
|
||||
void (*function)();
|
||||
}
|
||||
- initWithFunction: (void(*)())f
|
||||
argframe: (arglist_t)frame type: (const char *)e;
|
||||
- initWithFunction: (void(*)())f;
|
||||
@end
|
||||
|
||||
#if 0
|
||||
// NO, instead do above;
|
||||
@interface EltFunctionInvocation
|
||||
{
|
||||
void (*func)(elt);
|
||||
}
|
||||
- initWithEltFunction: (void(*)(elt))func;
|
||||
@end
|
||||
|
||||
@interface TclInvocation
|
||||
- initWithTcl: (Tcl*)t command: (const char*)c;
|
||||
@end
|
||||
|
||||
@interface Collection (Invokes)
|
||||
- makeObjectsInvoke: (MethodInvocation*)i;
|
||||
- withObjectsInvoke: (Invocation*)i;
|
||||
- withElementsInvoke: (EltInvocation*)i;
|
||||
@end
|
||||
#endif
|
||||
|
||||
#endif /* __Invocation_h_OBJECTS_INCLUDE */
|
285
Source/Invocation.m
Normal file
285
Source/Invocation.m
Normal file
|
@ -0,0 +1,285 @@
|
|||
|
||||
#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
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
- (void) invoke
|
||||
{
|
||||
void *ret;
|
||||
IMP imp;
|
||||
|
||||
imp = get_imp([self target], [self selector]);
|
||||
assert(imp);
|
||||
ret = __builtin_apply((void(*)(void))imp,
|
||||
argframe,
|
||||
type_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
|
82
Source/objects/Invocation.h
Normal file
82
Source/objects/Invocation.h
Normal file
|
@ -0,0 +1,82 @@
|
|||
#ifndef __Invocation_h_OBJECTS_INCLUDE
|
||||
#define __Invocation_h_OBJECTS_INCLUDE
|
||||
|
||||
/*
|
||||
Use these for notifications!
|
||||
Don't forget to make these archivable / transportable.
|
||||
WARNING: All the (char*) type arguments and return values may
|
||||
extraneous stuff after the first type.
|
||||
*/
|
||||
|
||||
#include <objects/stdobjects.h>
|
||||
#include <objects/Collection.h>
|
||||
|
||||
@interface Invocation : NSObject
|
||||
{
|
||||
char *encoding;
|
||||
unsigned return_size;
|
||||
void *return_value;
|
||||
}
|
||||
- initWithReturnType: (const char *)encoding;
|
||||
- (void) invoke;
|
||||
- (void) invokeWithObject: anObj;
|
||||
- (void) invokeWithElement: (elt)anElt;
|
||||
- (const char *) returnType;
|
||||
- (unsigned) returnSize;
|
||||
- (void) getReturnValue: (void *)addr;
|
||||
@end
|
||||
|
||||
@interface ArgframeInvocation : Invocation
|
||||
{
|
||||
arglist_t argframe;
|
||||
/* char *function_encoding; Using return_encoding */
|
||||
}
|
||||
- initWithArgframe: (arglist_t)frame type: (const char *)e;
|
||||
- initWithType: (const char *)e;
|
||||
- (const char *) argumentTypeAtIndex: (unsigned)i;
|
||||
- (unsigned) argumentSizeAtIndex: (unsigned)i;
|
||||
- (void) getArgument: (void*)addr atIndex: (unsigned)i;
|
||||
- (void) setArgumentAtIndex: (unsigned)i
|
||||
toValueAt: (const void*)addr;
|
||||
@end
|
||||
|
||||
@interface MethodInvocation : ArgframeInvocation
|
||||
- initWithArgframe: (arglist_t)frame selector: (SEL)s;
|
||||
- initWithSelector: (SEL)s;
|
||||
- (void) invokeWithTarget: t;
|
||||
- (SEL) selector;
|
||||
- (void) setSelector: (SEL)s;
|
||||
- target;
|
||||
- (void) setTarget: t;
|
||||
@end
|
||||
|
||||
@interface FunctionInvocation : ArgframeInvocation
|
||||
{
|
||||
void (*function)();
|
||||
}
|
||||
- initWithFunction: (void(*)())f
|
||||
argframe: (arglist_t)frame type: (const char *)e;
|
||||
- initWithFunction: (void(*)())f;
|
||||
@end
|
||||
|
||||
#if 0
|
||||
// NO, instead do above;
|
||||
@interface EltFunctionInvocation
|
||||
{
|
||||
void (*func)(elt);
|
||||
}
|
||||
- initWithEltFunction: (void(*)(elt))func;
|
||||
@end
|
||||
|
||||
@interface TclInvocation
|
||||
- initWithTcl: (Tcl*)t command: (const char*)c;
|
||||
@end
|
||||
|
||||
@interface Collection (Invokes)
|
||||
- makeObjectsInvoke: (MethodInvocation*)i;
|
||||
- withObjectsInvoke: (Invocation*)i;
|
||||
- withElementsInvoke: (EltInvocation*)i;
|
||||
@end
|
||||
#endif
|
||||
|
||||
#endif /* __Invocation_h_OBJECTS_INCLUDE */
|
Loading…
Add table
Add a link
Reference in a new issue