diff --git a/Headers/gnustep/base/NSGArray.h b/Headers/gnustep/base/NSGArray.h new file mode 100644 index 000000000..56c3526e1 --- /dev/null +++ b/Headers/gnustep/base/NSGArray.h @@ -0,0 +1,57 @@ +/* Interface to concrete implementation of NSArray. + Copyright (C) 1995 Free Software Foundation, Inc. + + Written by: R. Andrew McCallum + Date: March 1995 + + 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. + */ + +#ifndef __NSConcreteArray_h_OBJECTS_INCLUDE +#define __NSConcreteArray_h_OBJECTS_INCLUDE + +#include +#include +#include + +@interface NSConcreteArray : NSArray +{ + /* For now, these must match the instance variables in objects/Array.h. + This will change. */ + int (*_comparison_function)(elt,elt); + elt *_contents_array; + unsigned int _count; + unsigned int _capacity; + unsigned int _grow_factor; +} + +@end + +@interface NSConcreteMutableArray : NSArray +{ + /* For now, these must match the instance variables in objects/Array.h. + This will change. */ + int (*_comparison_function)(elt,elt); + elt *_contents_array; + unsigned int _count; + unsigned int _capacity; + unsigned int _grow_factor; +} + +@end + +#endif /* __NSConcreteArray_h_OBJECTS_INCLUDE */ diff --git a/Source/NSGArray.m b/Source/NSGArray.m new file mode 100644 index 000000000..acfe4974a --- /dev/null +++ b/Source/NSGArray.m @@ -0,0 +1,110 @@ +/* NSArray - Array object to hold other objects. + Copyright (C) 1995 Free Software Foundation, Inc. + + Written by: R. Andrew McCallum + Date: March 1995 + + 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 +#include +#include +#include +#include + +@implementation NSConcreteArray + ++ (void) initialize +{ + static int done = 0; + assert(!done); /* xxx see what the runtime is up to. */ + if (!done) + { + done = 1; + class_add_behavior([NSConcreteArray class], [Array class]); + } +} + +/* This is the designated initializer for NSArray. */ +- initWithObjects: (id*)objects count: (unsigned)count +{ + /* "super" call into IndexedCollection */ +#if 1 + CALL_METHOD_IN_CLASS([IndexedCollection class], initWithType:, + @encode(id)); +#else + (*(imp)) +#endif + _comparison_function = elt_get_comparison_function(@encode(id)); + _grow_factor = [[self class] defaultGrowFactor]; + _count = count; + _capacity = count; + OBJC_MALLOC(_contents_array, elt, _capacity); + while (count--) + _contents_array[count] = objects[count]; + return self; +} + +- (unsigned) count +{ + return _count; +} + +- objectAtIndex: (unsigned)index +{ + assert(index < _count); /* xxx should raise NSException instead */ + return _contents_array[index].id_u; +} + + +@end + +@implementation NSConcreteMutableArray + ++ (void) initialize +{ + static int done = 0; + if (!done) + { + done = 1; + class_add_behavior([NSConcreteMutableArray class], + [NSConcreteArray class]); + class_add_behavior([NSConcreteMutableArray class], [Array class]); + } +} + +- initWithCapacity: (unsigned)numItems +{ + /* "super" call into IndexedCollection */ + CALL_METHOD_IN_CLASS([IndexedCollection class], initWithType:, + @encode(id)); + _comparison_function = elt_get_comparison_function(@encode(id)); + _grow_factor = [[self class] defaultGrowFactor]; + _count = 0; + _capacity = numItems; + OBJC_MALLOC(_contents_array, elt, _capacity); + return self; +} + +/* Comes in from Array behavior + - (void) addObject: anObject + - (void)replaceObjectAtIndex: (unsigned)index withObject: anObject + - (void)insertObject: anObject atIndex: (unsigned)index + */ + +@end diff --git a/Source/argframe.m b/Source/argframe.m new file mode 100644 index 000000000..234277020 --- /dev/null +++ b/Source/argframe.m @@ -0,0 +1,426 @@ +#include +#include +#include + +/* These functions can be used for dissecting and making method calls + for many different situations. They are used for distributed + objects, they could also be used to make interfaces between + Objective C and Scheme, Perl, Tcl, whatever... I need to + generalize this stuff a little more to make it useable for an + Invocation class also. */ + +/* Returns YES iff there are any outparameters */ +BOOL +dissect_method_call(arglist_t frame, const char *type, + void (*f)(int,void*,const char*,int)) +{ + const char *tmptype; + unsigned flags; + char *datum; + int argnum; + + tmptype = type; + for (datum = my_method_get_next_argument(argframe, &tmptype), argnum=0; + datum; + datum = my_method_get_next_argument(argframe, &tmptype), argnum++) + { + flags = objc_get_type_qualifiers(tmptype); + tmptype = objc_skip_type_qualifiers(tmptype); + if (*tmptype == _C_ID) + { + (*f)(argnum, datum, tmptype, flags); + } + else if (*tmptype == _C_CHARPTR) + { + if ((flags & _F_OUT) || !(flags & _F_IN)) + out_parameters = YES; + if ((flags & _F_IN) || !(flags & _F_OUT)) + (*f)(argnum, datum, tmptype, flags); + } + else if (*tmptype == _C_PTR) + { + tmptype++; + if ((flags & _F_OUT) || !(flags & _F_IN)) + out_parameters = YES; + /* xxx These two cases currently the same */ + if (*tmptype == _C_STRUCT_B || *tmptype == _C_ARY_B) + { + if ((flags & _F_IN) || !(flags & _F_OUT)) + (*f)(argnum, *(void**)datum, tmptype, flags); + } + else + { + if ((flags & _F_IN) || !(flags & _F_OUT)) + (*f)(argnum, *(void**)datum, tmptype, flags); + } + } + else if (*tmptype == _C_STRUCT_B || *tmptype == _C_ARY_B) + { +#if CONNECTION_STRUCTURES_PASSED_BY_REFERENCE + (*f)(argnum, *(void**)datum, tmptype, flags); +#else + (*f)(argnum, datum, tmptype, flags); +#endif + } + else + { + (*f)(argnum, datum, tmptype, flags); + } + } + return out_parameters; +} + + +void +make_method_call(const char *forward_type, + void(*fd)(int,void*,const char*), + void(*fe)(int,void*,const char*,int)) +{ + const char *type, *tmptype; + const char *ftmptype; + id object; + SEL selector; + IMP imp; + void *retframe; + arglist_t argframe; + int stack_argsize; + int reg_argsize; + char *datum; + id op; + unsigned flags; + BOOL out_parameters = NO; + int argnum; + + /* get object and selector */ + (*fd)(0, &object, @encode(id)); + + /* @encode(SEL) produces "^v" in gcc 2.5.8. It should be ":" */ + (*fd)(1, &selector, ":"); + assert(selector); + + type = sel_get_type(selector); + assert(type); + + /* Set up argframe */ + stack_argsize = types_get_size_of_stack_arguments(type); + reg_argsize = types_get_size_of_register_arguments(type); + argframe = (arglist_t) alloca(sizeof(char*) + reg_argsize); + if (stack_argsize) + argframe->arg_ptr = alloca(stack_argsize); + else + argframe->arg_ptr = 0; + + /* decode rest of arguments */ + tmptype = type; + ftmptype = objc_skip_argspec(forward_type); + datum = my_method_get_next_argument(argframe, &tmptype); + assert(datum); + assert(*tmptype == _C_ID); + *(id*)datum = object; + assert(object); + ftmptype = objc_skip_argspec(ftmptype); + datum = my_method_get_next_argument(argframe, &tmptype); + assert(datum); + assert(*tmptype == _C_SEL); + *(SEL*)datum = selector; + assert(selector); + for (datum = my_method_get_next_argument(argframe, &tmptype), + ftmptype = objc_skip_argspec(ftmptype), argnum = 2; + datum; + datum = my_method_get_next_argument(argframe, &tmptype), + ftmptype = objc_skip_argspec(ftmptype), argnum++) + { + flags = objc_get_type_qualifiers(ftmptype); + tmptype = objc_skip_type_qualifiers(tmptype); + if (*tmptype == _C_CHARPTR) + { + if ((flags & _F_OUT) || !(flags & _F_IN)) + out_parameters = YES; + if ((flags & _F_IN) || !(flags & _F_OUT)) + (*fd)(argnum, datum, tmptype); + } + else if (*tmptype == _C_PTR) + { + tmptype++; + if ((flags & _F_OUT) || !(flags & _F_IN)) + out_parameters = YES; + /* xxx These two cases currently the same */ + if (*tmptype == _C_STRUCT_B || *tmptype == _C_ARY_B) + { + /* *(void**)datum = alloca(sizeof(void*)); */ + /* xxx or should this be alloca?! + What about inout params? Where do they get freed? */ + *(void**)datum = + (*objc_malloc)(objc_sizeof_type(tmptype)); + if ((flags & _F_IN) || !(flags & _F_OUT)) + (*fd)(argnum, *(void**)datum, tmptype); + } + else + { + /* xxx or should this be alloca?! + What about inout params? Where dothey get freed? */ + *(char**)datum = + (*objc_malloc)(objc_sizeof_type(tmptype)); + if ((flags & _F_IN) || !(flags & _F_OUT)) + (*fd)(argnum, *(void**)datum, tmptype); + } + } + else if (*tmptype == _C_STRUCT_B || *tmptype == _C_ARY_B) + { +#if CONNECTION_STRUCTURES_PASSED_BY_REFERENCE + *(void**)datum = alloca(objc_sizeof_type(tmptype)); + (*fd)(argnum, *(void**)datum, tmptype); +#else + (*fd)(argnum, datum, tmptype); +#endif + } + else + { + (*fd)(argnum, datum, tmptype); + } + } + + /* Call the method */ + imp = objc_msg_lookup(object, selector); + assert(imp); + retframe = __builtin_apply((apply_t)imp, + argframe, + stack_argsize); + + /* Return results, if necessary */ + flags = objc_get_type_qualifiers(forward_type); + ftmptype = objc_skip_type_qualifiers(forward_type); + tmptype = objc_skip_type_qualifiers(type); + /* Is this right? Do we also have to check _F_ONEWAY? */ + if (out_parameters || *tmptype != _C_VOID) + { + if (*tmptype != _C_VOID) + { + /* encode return value */ + /* xxx Change this to switch(*tmptype) */ + if (*tmptype == _C_ID) + { + (*fe)(-1, retframe, @encode(id), flags); + } + else if (*tmptype == _C_PTR) + { + tmptype++; + /* xxx These two cases currently the same */ + if (*tmptype == _C_STRUCT_B || *tmptype == _C_ARY_B) + (*fe)(-1, *(void**)retframe, tmptype, flags); + else + (*fe)(-1, *(void**)retframe, tmptype, flags); + } + else if (*tmptype == _C_STRUCT_B || *tmptype == _C_ARY_B) + { + /* xxx these two cases currently the same? */ +#if CONNECTION_STRUCTURES_PASSED_BY_REFERENCE + (*fe)(-1, *(void**)retframe, tmptype, flags); +#else + (*fe)(-1, *(void**)retframe, tmptype, flags); +#endif + } + else if (*tmptype == _C_FLT || *tmptype == _C_DBL) + { + (*fe)(-1, ((char*)retframe) + FLT_AND_DBL_RETFRAME_OFFSET + tmptype, flags); + } + else /* Among other types, _C_CHARPTR is handled here */ + { + int retsize = objc_sizeof_type(tmptype); + /* Special case BOOL (and other types smaller than int) + because retframe doesn't actually point to the char */ + /* xxx What about structures smaller than int's that + are passed by reference on true structure reference- + passing architectures? */ + /* xxx Is this the right test? Use sizeof(int*) instead? */ + if (retsize < sizeof(void*)) + { + (*fe)(-1, ((char*)retframe)+sizeof(void*)-retsize + tmptype, flags); + } + else + { + (*fe)(-1, retframe, tmptype, flags); + } + } + } + + /* encode values returned by reference */ + if (out_parameters) + { + for (datum = my_method_get_next_argument(argframe,&tmptype), + argnum = 1, + ftmptype = objc_skip_argspec(ftmptype); + datum; + datum = my_method_get_next_argument(argframe,&tmptype), + argnum++, + ftmptype = objc_skip_argspec(ftmptype)) + { + flags = objc_get_type_qualifiers(ftmptype); + tmptype = objc_skip_type_qualifiers(tmptype); + sprintf(argname, "arg%d", argnum); /* too expensive? */ + if ((*tmptype == _C_PTR) + && ((flags & _F_OUT) || !(flags & _F_IN))) + { + tmptype++; + /* xxx These two cases currently the same */ + if (*tmptype == _C_STRUCT_B || *tmptype == _C_ARY_B) + { + (*fe)(argnum, *(void**)datum, tmptype, flags); + } + else + { + (*fe)(argnum, *(void**)datum, tmptype, flags); + } + } + else if (*tmptype == _C_CHARPTR + && ((flags & _F_OUT) || !(flags & _F_IN))) + { + (*fe)(argnum, datum, tmptype, flags); + } + } + } + } + return self; +} + + +void f_decode_rets (int argnum, void *datum, const char *type) +{ + [ip decodeValueOfType:type + at:datum + withName:NULL]; +} + +/* In the function that calls this one, be careful about calling more + functions after this one. The memory for the retval_t is alloca'ed */ +retval_t dissect_method_return(arglist_t frame, const char *type, + BOOL out_parameters, + void(*f)(int,void*,const char*,int)) +{ + retval_t retframe; + int argnum; + int flags; + const char *tmptype; + + /* get return values, if necessary */ + flags = objc_get_type_qualifiers(type); + tmptype = objc_skip_type_qualifiers(type); + /* xxx What happens with method declared "- (oneway) foo: (out int*)ip;" */ + /* xxx What happens with method declared "- (in char *) bar;" */ + /* Is this right? Do we also have to check _F_ONEWAY? */ + if (out_parameters || *tmptype != _C_VOID) + { + argnum = -1 + if (*tmptype != _C_VOID) + { + /* decode return value */ + retsize = objc_sizeof_type(tmptype); + /* xxx We need to test retsize's less than 4. Also note that + if we return structures using a structure-value-address, we + are potentially alloca'ing much more than we need here. */ + /* xxx Find out about returning structures by reference + on non--structure-value-address machines, and potentially + just always alloca(RETFRAME_SIZE == sizeof(void*)*4) */ + retframe = alloca(MAX(retsize, sizeof(void*)*4)); + /* xxx change this to a switch (*tmptype) */ + if (*tmptype == _C_PTR) + { + tmptype++; + /* xxx these two cases are the same */ + if (*tmptype == _C_STRUCT_B || *tmptype == _C_ARY_B) + { + *(void**)retframe = + (*objc_malloc)(objc_sizeof_type(tmptype)); + (*f)(argnum, *(void**)retframe, tmptype, flags); + } + else + { + *(void**)retframe = + (*objc_malloc)(objc_sizeof_type(tmptype)); + (*f)(argnum, *(void**)retframe, tmptype, flags); + } + } + else if (*tmptype == _C_STRUCT_B || *tmptype == _C_ARY_B) + { + /* xxx These two cases currently the same */ + xxx wwoooooo, we have to alloca in the frame above +#if CONNECTION_STRUCTURES_PASSED_BY_REFERENCE + *(void**)retframe = alloca(objc_sizeof_type(tmptype)); + (*f)(argnum, *(void**)retframe, tmptype, flags); +#else + *(void**)retframe = alloca(objc_sizeof_type(tmptype)); + (*f)(argnum, *(void**)retframe, tmptype, flags); +#endif + } + else if (*tmptype == _C_FLT || *tmptype == _C_DBL) + { + (*f)(argnum, ((char*)retframe) + FLT_AND_DBL_RETFRAME_OFFSET, + tmptype, flags); + } + else /* Among other things, _C_CHARPTR is handled here */ + { + /* int typesize; xxx Use retsize instead! */ + /* xxx was: (typesize = objc_sizeof_type(tmptype)) */ + /* Special case BOOL (and other types smaller than int) + because retframe doesn't actually point to the char */ + /* xxx What about structures smaller than int's that + are passed by reference on true structure reference- + passing architectures? */ + /* xxx Is this the right test? Use sizeof(int*) instead? */ + if (retsize < sizeof(void*)) + { + *(void**)retframe = 0; + (*f)(argnum, ((char*)retframe)+sizeof(void*)-retsize, + tmptype, flags); + } + else + { + (*f)(argnum, retframe, tmptype, flags); + } + } + } + + /* decode values returned by reference */ + if (out_parameters) + { + for (datum = my_method_get_next_argument(argframe, &tmptype), argnum=0; + datum; + (datum = my_method_get_next_argument(argframe, &tmptype)), argnum++) + { + flags = objc_get_type_qualifiers(tmptype); + tmptype = objc_skip_type_qualifiers(tmptype); + if (*tmptype == _C_PTR + && ((flags & _F_OUT) || !(flags & _F_IN))) + { + tmptype++; + /* xxx Note that a (char**) is malloc'ed anew here. + Yucky, or worse than yucky. If the returned string + is smaller than the original, we should just put it + there; if the returned string is bigger, I don't know + what to do. */ + /* xxx These two cases are the same */ + if (*tmptype == _C_STRUCT_B || *tmptype == _C_ARY_B) + { + (*f)(argnum, *(void**)datum, tmptype, flags); + } + else + { + (*f)(argnum, *(void**)datum, tmptype, flags); + } + } + /* __builtin_return can't return structures by value */ + else if (*tmptype == _C_CHARPTR + && ((flags & _F_OUT) || !(flags & _F_IN))) + { + (*f)(argnum, datum, tmptype, flags); + } + } + } + } + else /* void return value */ + { + retframe = alloca(sizeof(void*)); + } +} diff --git a/Source/objects/NSString.h b/Source/objects/NSString.h new file mode 100644 index 000000000..982acf85c --- /dev/null +++ b/Source/objects/NSString.h @@ -0,0 +1,40 @@ +/* GNU extensions to NSString. + Copyright (C) 1995 Free Software Foundation, Inc. + + Written by: R. Andrew McCallum + Date: March 1995 + + 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. +*/ + +/* You can include this instead of (or in addition to) + foundation/NSString.h if you want to use the GNU extensions. The + primary GNU extention is that NSString objects now conform to + IndexedCollecting---they are Collection objects just like in + Smalltalk. */ + +#ifndef __objects_NSString_h_OBJECTS_INCLUDE +#define __objects_NSString_h_OBJECTS_INCLUDE + +#include +#include +#include + +@interface NSString (GNU) +@end + +#endif /* __objects_NSString_h_OBJECTS_INCLUDE */ diff --git a/Testing/nsarray.m b/Testing/nsarray.m new file mode 100644 index 000000000..878921009 --- /dev/null +++ b/Testing/nsarray.m @@ -0,0 +1,30 @@ +#include + +int +main() +{ + id a, b; + + set_behavior_debug(1); + a = [NSArray arrayWithObjects: + [NSObject class], + [NSArray class], + [NSMutableArray class]]; + + printf("NSArray has count %d\n", [a count]); + printf("Classname at index 1 is %s\n", [[a objectAtIndex:1] name]); + + assert([a containsObject:[NSObject class]]); + assert([a lastObject]); + [a makeObjectsPerform:@selector(self)]; + + b = [a mutableCopy]; + assert([b count]); + [b addObject:[NSObject class]]; + [b removeObject:[NSArray class]]; + [b removeLastObject]; + + assert([b firstObjectCommonWithArray:a]); + + exit(0); +}