From cc36fcd0ee30c6354846605f7dce730cb9749b14 Mon Sep 17 00:00:00 2001 From: fedor Date: Tue, 8 Aug 2000 14:11:01 +0000 Subject: [PATCH] Obsolete files git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@7189 72102866-910b-0410-8b05-ffd578937521 --- Old/Archiver.h | 41 + Old/Archiver.m | 38 + Old/Array.h | 72 + Old/Array.m | 263 ++ Old/ArrayPrivate.h | 87 + Old/Bag.h | 50 + Old/Bag.m | 211 ++ Old/BinaryCStream.h | 42 + Old/BinaryCStream.m | 646 ++++ Old/BinaryTree.h | 76 + Old/BinaryTree.m | 607 ++++ Old/BinaryTreeNode.h | 40 + Old/BinaryTreeNode.m | 104 + Old/CStream.h | 62 + Old/CStream.m | 287 ++ Old/CStreaming.h | 59 + Old/CircularArray.h | 37 + Old/CircularArray.m | 197 ++ Old/CircularArrayPrivate.h | 74 + Old/Coder.h | 141 + Old/Coder.m | 310 ++ Old/CoderPrivate.h | 66 + Old/Coding.h | 165 ++ Old/Collecting.h | 129 + Old/Collection.h | 102 + Old/Collection.m | 839 ++++++ Old/CollectionPrivate.h | 50 + Old/Decoder.m | 878 ++++++ Old/DelegatePool.h | 74 + Old/DelegatePool.m | 210 ++ Old/Dictionary.h | 40 + Old/Dictionary.m | 209 ++ Old/Encoder.m | 883 ++++++ Old/Enumerating.h | 36 + Old/GapArray.h | 38 + Old/GapArray.m | 144 + Old/GapArrayPrivate.h | 88 + Old/Heap.h | 36 + Old/Heap.m | 102 + Old/IndexedCollecting.h | 132 + Old/IndexedCollection.h | 110 + Old/IndexedCollection.m | 466 +++ Old/IndexedCollectionPrivate.h | 40 + Old/InvalidationListening.h | 38 + Old/Invocation.h | 98 + Old/Invocation.m | 861 ++++++ Old/Invoking.h | 42 + Old/KeyedCollecting.h | 81 + Old/KeyedCollection.h | 79 + Old/KeyedCollection.m | 280 ++ Old/LinkedList.h | 50 + Old/LinkedList.m | 408 +++ Old/LinkedListNode.h | 38 + Old/LinkedListNode.m | 84 + Old/Locking.h | 34 + Old/MachPort.h | 39 + Old/MachPort.m | 196 ++ Old/Magnitude.h | 33 + Old/Magnitude.m | 99 + Old/MappedCollector.h | 40 + Old/MappedCollector.m | 138 + Old/MemoryStream.h | 90 + Old/MemoryStream.m | 435 +++ Old/NotificationDispatcher.h | 221 ++ Old/NotificationDispatcher.m | 750 +++++ Old/OldNSConnection.h | 558 ++++ Old/OldNSConnection.m | 5072 ++++++++++++++++++++++++++++++++ Old/OldNSPortCoder.h | 147 + Old/OldNSPortCoder.m | 2437 +++++++++++++++ Old/OrderedCollecting.h | 65 + Old/OrderedCollection.h | 38 + Old/OrderedCollection.m | 265 ++ Old/Ordering.h | 47 + Old/Port.h | 119 + Old/Port.m | 210 ++ Old/Queue.h | 36 + Old/Queue.m | 48 + Old/RBTree.h | 39 + Old/RBTree.m | 250 ++ Old/RBTreeNode.h | 36 + Old/RBTreeNode.m | 87 + Old/README | 13 + Old/RNGAdditiveCongruential.h | 43 + Old/RNGAdditiveCongruential.m | 112 + Old/RNGBerkeley.h | 73 + Old/RNGBerkeley.m | 443 +++ Old/Random.h | 68 + Old/Random.m | 306 ++ Old/RandomGenerating.h | 36 + Old/RawCStream.h | 36 + Old/RawCStream.m | 296 ++ Old/Retaining.h | 100 + Old/RunLoop.h | 9 + Old/Set.h | 52 + Old/Set.m | 229 ++ Old/SplayTree.h | 47 + Old/SplayTree.m | 102 + Old/Stack.h | 40 + Old/Stack.m | 66 + Old/StdioStream.h | 55 + Old/StdioStream.m | 309 ++ Old/Stream.h | 38 + Old/Stream.m | 168 ++ Old/Streaming.h | 75 + Old/TcpPort.h | 90 + Old/TcpPort.m | 1609 ++++++++++ Old/TextCStream.h | 34 + Old/TextCStream.m | 421 +++ Old/Time.h | 101 + Old/UdpPort.h | 62 + Old/UdpPort.m | 479 +++ Old/ValueHolding.h | 50 + Old/all.h | 65 + Old/cstream.m | 57 + Old/invocation.m | 107 + Old/invocation_char.m | 181 ++ Old/invocation_int.m | 181 ++ Old/invocation_long.m | 181 ++ Old/invocation_short.m | 179 ++ Old/ostream.h | 84 + Old/ostream.m | 366 +++ Old/pipes.m | 17 + 122 files changed, 28849 insertions(+) create mode 100644 Old/Archiver.h create mode 100644 Old/Archiver.m create mode 100644 Old/Array.h create mode 100644 Old/Array.m create mode 100644 Old/ArrayPrivate.h create mode 100644 Old/Bag.h create mode 100644 Old/Bag.m create mode 100644 Old/BinaryCStream.h create mode 100644 Old/BinaryCStream.m create mode 100644 Old/BinaryTree.h create mode 100644 Old/BinaryTree.m create mode 100644 Old/BinaryTreeNode.h create mode 100644 Old/BinaryTreeNode.m create mode 100644 Old/CStream.h create mode 100644 Old/CStream.m create mode 100644 Old/CStreaming.h create mode 100644 Old/CircularArray.h create mode 100644 Old/CircularArray.m create mode 100644 Old/CircularArrayPrivate.h create mode 100644 Old/Coder.h create mode 100644 Old/Coder.m create mode 100644 Old/CoderPrivate.h create mode 100644 Old/Coding.h create mode 100644 Old/Collecting.h create mode 100644 Old/Collection.h create mode 100644 Old/Collection.m create mode 100644 Old/CollectionPrivate.h create mode 100644 Old/Decoder.m create mode 100644 Old/DelegatePool.h create mode 100644 Old/DelegatePool.m create mode 100644 Old/Dictionary.h create mode 100644 Old/Dictionary.m create mode 100644 Old/Encoder.m create mode 100644 Old/Enumerating.h create mode 100644 Old/GapArray.h create mode 100644 Old/GapArray.m create mode 100644 Old/GapArrayPrivate.h create mode 100644 Old/Heap.h create mode 100644 Old/Heap.m create mode 100644 Old/IndexedCollecting.h create mode 100644 Old/IndexedCollection.h create mode 100644 Old/IndexedCollection.m create mode 100644 Old/IndexedCollectionPrivate.h create mode 100644 Old/InvalidationListening.h create mode 100644 Old/Invocation.h create mode 100644 Old/Invocation.m create mode 100644 Old/Invoking.h create mode 100644 Old/KeyedCollecting.h create mode 100644 Old/KeyedCollection.h create mode 100644 Old/KeyedCollection.m create mode 100644 Old/LinkedList.h create mode 100644 Old/LinkedList.m create mode 100644 Old/LinkedListNode.h create mode 100644 Old/LinkedListNode.m create mode 100644 Old/Locking.h create mode 100644 Old/MachPort.h create mode 100644 Old/MachPort.m create mode 100644 Old/Magnitude.h create mode 100644 Old/Magnitude.m create mode 100644 Old/MappedCollector.h create mode 100644 Old/MappedCollector.m create mode 100644 Old/MemoryStream.h create mode 100644 Old/MemoryStream.m create mode 100644 Old/NotificationDispatcher.h create mode 100644 Old/NotificationDispatcher.m create mode 100644 Old/OldNSConnection.h create mode 100644 Old/OldNSConnection.m create mode 100644 Old/OldNSPortCoder.h create mode 100644 Old/OldNSPortCoder.m create mode 100644 Old/OrderedCollecting.h create mode 100644 Old/OrderedCollection.h create mode 100644 Old/OrderedCollection.m create mode 100644 Old/Ordering.h create mode 100644 Old/Port.h create mode 100644 Old/Port.m create mode 100644 Old/Queue.h create mode 100644 Old/Queue.m create mode 100644 Old/RBTree.h create mode 100644 Old/RBTree.m create mode 100644 Old/RBTreeNode.h create mode 100644 Old/RBTreeNode.m create mode 100644 Old/README create mode 100644 Old/RNGAdditiveCongruential.h create mode 100644 Old/RNGAdditiveCongruential.m create mode 100644 Old/RNGBerkeley.h create mode 100644 Old/RNGBerkeley.m create mode 100644 Old/Random.h create mode 100644 Old/Random.m create mode 100644 Old/RandomGenerating.h create mode 100644 Old/RawCStream.h create mode 100644 Old/RawCStream.m create mode 100644 Old/Retaining.h create mode 100644 Old/RunLoop.h create mode 100644 Old/Set.h create mode 100644 Old/Set.m create mode 100644 Old/SplayTree.h create mode 100644 Old/SplayTree.m create mode 100644 Old/Stack.h create mode 100644 Old/Stack.m create mode 100644 Old/StdioStream.h create mode 100644 Old/StdioStream.m create mode 100644 Old/Stream.h create mode 100644 Old/Stream.m create mode 100644 Old/Streaming.h create mode 100644 Old/TcpPort.h create mode 100644 Old/TcpPort.m create mode 100644 Old/TextCStream.h create mode 100644 Old/TextCStream.m create mode 100644 Old/Time.h create mode 100644 Old/UdpPort.h create mode 100644 Old/UdpPort.m create mode 100644 Old/ValueHolding.h create mode 100644 Old/all.h create mode 100644 Old/cstream.m create mode 100644 Old/invocation.m create mode 100644 Old/invocation_char.m create mode 100644 Old/invocation_int.m create mode 100644 Old/invocation_long.m create mode 100644 Old/invocation_short.m create mode 100644 Old/ostream.h create mode 100644 Old/ostream.m create mode 100644 Old/pipes.m diff --git a/Old/Archiver.h b/Old/Archiver.h new file mode 100644 index 000000000..c8beebb80 --- /dev/null +++ b/Old/Archiver.h @@ -0,0 +1,41 @@ +/* Interface for GNU Objective-C Archiver object for use serializing + Copyright (C) 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: January 1996 + + 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 __Archiver_h_GNUSTEP_BASE_INCLUDE +#define __Archiver_h_GNUSTEP_BASE_INCLUDE + +#include + +/* Eventually some functionality may be moved out of Coder and + into these objects. + + These class should be used as concrete classes, not the Coder class. */ + + +@interface Archiver : Encoder +@end + +@interface Unarchiver : Decoder +@end + +#endif /* __Archiver_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/Archiver.m b/Old/Archiver.m new file mode 100644 index 000000000..4191a20b8 --- /dev/null +++ b/Old/Archiver.m @@ -0,0 +1,38 @@ +/* Implementation of GNU Objective-C class for writing objects to files + Copyright (C) 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: January 1996 + + 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. + */ + +#include +#include +#include + +/* Eventually some functionality may be moved out of Encoder and + Decoder and into these objects. + + These class should be used as concrete classes, not the Coder, + Encoder or Decoder classes. */ + +@implementation Archiver +@end + +@implementation Unarchiver +@end diff --git a/Old/Array.h b/Old/Array.h new file mode 100644 index 000000000..188866a22 --- /dev/null +++ b/Old/Array.h @@ -0,0 +1,72 @@ +/* Interface for Objective-C Array collection object + Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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 __Array_h_GNUSTEP_BASE_INCLUDE +#define __Array_h_GNUSTEP_BASE_INCLUDE + +#include +#include + +@interface ConstantArray : ConstantIndexedCollection +{ + @public + id *_contents_array; + unsigned int _count; +} +@end + +@interface Array : ConstantArray +{ + @public + unsigned int _capacity; + int _grow_factor; +} + ++ (unsigned) defaultCapacity; ++ (int) defaultGrowFactor; + +- initWithCapacity: (unsigned) aCapacity; + +- (void) setCapacity: (unsigned)newCapacity; +- (int) growFactor; +- (void) setGrowFactor: (int)aNum; + +@end + +/* Put this on category instead of class to avoid bogus complaint from gcc */ +@interface Array (Ordering) +@end + +#define FOR_ARRAY(ARRAY, ELEMENT_VAR) \ +{ \ + unsigned _FOR_ARRAY_i; \ + for (_FOR_ARRAY_i = 0; \ + _FOR_ARRAY_i < ((Array*)ARRAY)->_count; \ + _FOR_ARRAY_i++) \ + { \ + ELEMENT_VAR = \ + (((Array*)ARRAY)->_contents_array[_FOR_ARRAY_i]); + +#define END_FOR_ARRAY(ARRAY) }} + +#endif /* __Array_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/Array.m b/Old/Array.m new file mode 100644 index 000000000..a07b6d173 --- /dev/null +++ b/Old/Array.m @@ -0,0 +1,263 @@ +/* Implementation for Objective-C Array collection object + Copyright (C) 1993,1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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. +*/ + +#include +#include +#include +#include +#include +#include + +@implementation ConstantArray + +/* This is the designated initializer of this class */ +- initWithObjects: (id*)objs count: (unsigned)c +{ + _count = c; + OBJC_MALLOC(_contents_array, id, _count); + while (c--) + _contents_array[c] = objs[c]; + return self; +} + +/* Empty copy must empty an allocCopy'ed version of self */ +- emptyCopy +{ + Array *copy = [super emptyCopy]; + copy->_count = 0; + OBJC_MALLOC(copy->_contents_array, id, copy->_capacity); + return copy; +} + +- (void) _collectionDealloc +{ + OBJC_FREE(_contents_array); + [super _collectionDealloc]; +} + + +// GETTING ELEMENTS BY INDEX; + +- objectAtIndex: (unsigned)index +{ + CHECK_INDEX_RANGE_ERROR(index, _count); + return _contents_array[index]; +} + + +// TESTING; + +- (unsigned) count +{ + return _count; +} + +@end + + +@implementation Array + ++ (void) initialize +{ + if (self == [Array class]) + class_add_behavior (self, [OrderedCollection class]); +} + +// MANAGING CAPACITY; + +/* Eventually we will want to have better capacity management, + potentially keep default capacity as a class variable. */ + ++ (unsigned) defaultCapacity +{ + return DEFAULT_ARRAY_CAPACITY; +} + ++ (int) defaultGrowFactor +{ + return DEFAULT_ARRAY_GROW_FACTOR; +} + +/* This is the designated initializer for this class */ +- initWithCapacity: (unsigned)aCapacity +{ + _grow_factor = [[self class] defaultGrowFactor]; + _count = 0; + _capacity = (aCapacity < 1) ? 1 : aCapacity; + OBJC_MALLOC(_contents_array, id, _capacity); + return self; +} + +/* Archiving must mimic the above designated initializer */ + +- (void) _encodeCollectionWithCoder: (id )coder +{ + [super _encodeCollectionWithCoder:coder]; + [coder encodeValueOfCType:@encode(unsigned) + at:&_grow_factor + withName:@"Array Grow Factor"]; + [coder encodeValueOfCType:@encode(unsigned) + at:&_capacity + withName:@"Array Capacity"]; +} + +- _initCollectionWithCoder: (id )coder +{ + [super _initCollectionWithCoder:coder]; + [coder decodeValueOfCType:@encode(unsigned) + at:&_grow_factor + withName:NULL]; + _count = 0; + [coder decodeValueOfCType:@encode(unsigned) + at:&_capacity + withName:NULL]; + return self; +} + +/* Override superclass' designated initializer to call ours */ +- initWithObjects: (id*)objs count: (unsigned)c +{ + int i; + [self initWithCapacity: c]; + for (i = 0; i < c; i++) + [self insertObject: objs[i] atIndex: i]; // xxx this most efficient method? + return self; +} + +/* This must work without sending any messages to content objects */ +- (void) empty +{ + int i; + + for (i = 0; i < _count; i++) + [_contents_array[i] release]; + _count = 0; + /* Note this may not work for subclassers. Beware. */ +} + +// MANAGING CAPACITY; + +/* This is the only method that changes the value of the instance + variable _capacity, except for "-initDescription:capacity:" */ + +- (void) setCapacity: (unsigned)newCapacity +{ + if (newCapacity > _count) { + _capacity = newCapacity; + OBJC_REALLOC(_contents_array, id, _capacity); + } +} + +- (int) growFactor +{ + return _grow_factor; +} + +- (void) setGrowFactor: (int)aNum; +{ + _grow_factor = aNum; +} + + +// ADDING; + +- (void) appendObject: newObject +{ + /* Check to make sure that anObject is not nil, first. */ + if (newObject == nil) + { + [NSException raise: NSInvalidArgumentException + format: @"Array: object to add is nil" + ]; + } + + /* Now we can add it. */ + incrementCount(self); + [newObject retain]; + _contents_array[_count-1] = newObject; +} + +- (void) prependObject: newObject +{ + incrementCount(self); + [newObject retain]; + makeHoleAt(self, 0); + _contents_array[0] = newObject; +} + +- (void) insertObject: newObject atIndex: (unsigned)index +{ + CHECK_INDEX_RANGE_ERROR(index, _count+1); + + /* Check to make sure that anObject is not nil, first. */ + if (newObject == nil) + { + [NSException raise: NSInvalidArgumentException + format: @"Array: object to insert is nil" + ]; + } + + incrementCount(self); + [newObject retain]; + makeHoleAt(self, index); + _contents_array[index] = newObject; +} + + +// REMOVING, REPLACING AND SWAPPING; + +- (void) removeObjectAtIndex: (unsigned)index +{ + CHECK_INDEX_RANGE_ERROR(index, _count); + [_contents_array[index] release]; + fillHoleAt(self, index); + decrementCount(self); +} + +/* We could be more efficient if we override these also. + - removeFirstObject + - removeLastObject; + If you do, remember, you will have to implement this methods + in GapArray also! */ + + +- (void) replaceObjectAtIndex: (unsigned)index withObject: newObject +{ + CHECK_INDEX_RANGE_ERROR(index, _count); + [newObject retain]; + [_contents_array[index] release]; + _contents_array[index] = newObject; +} + +- (void) swapAtIndeces: (unsigned)index1 : (unsigned)index2 +{ + id tmp; + + CHECK_INDEX_RANGE_ERROR(index1, _count); + CHECK_INDEX_RANGE_ERROR(index2, _count); + tmp = _contents_array[index1]; + _contents_array[index1] = _contents_array[index2]; + _contents_array[index2] = tmp; +} + +@end diff --git a/Old/ArrayPrivate.h b/Old/ArrayPrivate.h new file mode 100644 index 000000000..61ffb54e9 --- /dev/null +++ b/Old/ArrayPrivate.h @@ -0,0 +1,87 @@ +/* Array definitions for the use of subclass implementations only + Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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 __ArrayPrivate_h_GNUSTEP_BASE_INCLUDE +#define __ArrayPrivate_h_GNUSTEP_BASE_INCLUDE + +#include + +#define DEFAULT_ARRAY_CAPACITY 2 +#define DEFAULT_ARRAY_GROW_FACTOR 2 + + +/* Routines that help with inserting and removing elements */ + +/* Assumes that _count has already been incremented to make room + for the hole. The data at _contents_array[_count-1] is not part + of the collection). */ +static inline void +makeHoleAt(Array *self, unsigned index) +{ + int i; + + for (i = (self->_count)-1; i > index; i--) + self->_contents_array[i] = self->_contents_array[i-1]; +} + +/* Assumes that _count has not yet been decremented. The data at + _contents_array[_count-1] is part of the collection. */ +static inline void +fillHoleAt(Array *self, unsigned index) +{ + int i; + + for (i = index; i < (self->_count)-1; i++) + self->_contents_array[i] = self->_contents_array[i+1]; +} + +/* These are the only two routines that change the value of the instance + variable _count, except for "-initWithType:capacity:" and "-empty" */ + +/* Should these be methods instead of functions? Doing so would make + them slower. */ + +/* Do this before adding an element */ +static inline void +incrementCount(Array *self) +{ + (self->_count)++; + if (self->_count == self->_capacity) + { + [self setCapacity:(self->_capacity) * ABS(self->_grow_factor)]; + } +} + +/* Do this after removing an element */ +static inline void +decrementCount(Array *self) +{ + (self->_count)--; + if (self->_grow_factor > 0 + && self->_count < (self->_capacity / self->_grow_factor)) + { + [self setCapacity:(self->_capacity) / self->_grow_factor]; + } +} + +#endif /* __ArrayPrivate_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/Bag.h b/Old/Bag.h new file mode 100644 index 000000000..0f3abc4dc --- /dev/null +++ b/Old/Bag.h @@ -0,0 +1,50 @@ +/* Interface for Objective-C Bag collection object + Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: May 1993 + + 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 __Bag_h_GNUSTEP_BASE_INCLUDE +#define __Bag_h_GNUSTEP_BASE_INCLUDE + +#include +#include + +@interface Bag : Collection +{ + NSMapTable *_contents_map; + unsigned int _count; // the number of elements; +} + +// INITIALIZING AND FREEING; +- initWithCapacity: (unsigned)aCapacity; + +// ADDING; +- (void) addObject: newObject withOccurrences: (unsigned)count; + +// REMOVING AND REPLACING; +- (void) removeObject: oldObject occurrences: (unsigned)count; + +// TESTING; +- (unsigned) uniqueCount; + +@end + +#endif /* __Bag_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/Bag.m b/Old/Bag.m new file mode 100644 index 000000000..e62df8b67 --- /dev/null +++ b/Old/Bag.m @@ -0,0 +1,211 @@ +/* Implementation for Objective-C Bag collection object + Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: May 1993 + + 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. +*/ + +#include +#include +#include + +#define DEFAULT_BAG_CAPACITY 32 + +@implementation Bag + +// MANAGING CAPACITY; + +/* Eventually we will want to have better capacity management, + potentially keep default capacity as a class variable. */ + ++ (unsigned) defaultCapacity +{ + return DEFAULT_BAG_CAPACITY; +} + +// INITIALIZING AND FREEING; + +/* This is the designated initializer of this class */ +/* Override designated initializer of superclass */ +- initWithCapacity: (unsigned)cap +{ + _contents_map = NSCreateMapTable (NSObjectMapKeyCallBacks, + NSIntMapValueCallBacks, + cap); + _count = 0; + return self; +} + +/* Override Collection's designated initializer */ +- initWithObjects: (id*)objs count: (unsigned)count +{ + [self initWithCapacity: count]; + while (count--) + [self addObject: objs[count]]; + return self; +} + + +/* Archiving must mimic the above designated initializer */ + +/* Archiving must mimic the above designated initializer */ + +- (void) encodeWithCoder: anEncoder +{ + [self notImplemented:_cmd]; +} + +- initWithCoder: aDecoder +{ + [self notImplemented:_cmd]; + return self; +} + +/* Empty copy must empty an allocCopy'ed version of self */ +- emptyCopy +{ + Bag *copy = [super emptyCopy]; + copy->_contents_map = NSCreateMapTable (NSObjectMapKeyCallBacks, + NSIntMapValueCallBacks, + 0); + copy->_count = 0; + return copy; +} + +- (void) dealloc +{ + NSFreeMapTable (_contents_map); + [super _collectionDealloc]; +} + +/* This must work without sending any messages to content objects */ +- (void) _collectionEmpty +{ + NSResetMapTable (_contents_map); + _count = 0; +} + +// ADDING; + +- (void) addObject: newObject withOccurrences: (unsigned)count +{ + unsigned new_count = (unsigned) NSMapGet (_contents_map, newObject); + new_count += count; + NSMapInsert (_contents_map, newObject, (void*)new_count); + _count += count; +} + +- (void) addObject: newObject +{ + [self addObject: newObject withOccurrences: 1]; +} + + +// REMOVING AND REPLACING; + +- (void) removeObject: oldObject occurrences: (unsigned)count +{ + unsigned c = (unsigned) NSMapGet (_contents_map, oldObject); + if (c) + { + if (c <= count) + { + NSMapRemove (_contents_map, oldObject); + _count -= c; + } + else + { + NSMapInsert (_contents_map, oldObject, (void*)(c - count)); + _count -= count; + } + } +} + +- (void) removeObject: oldObject +{ + [self removeObject: oldObject occurrences:1]; +} + +- (void) uniqueContents +{ + [self notImplemented: _cmd]; +} + + +// TESTING; + +- (unsigned) count +{ + return _count; +} + +- (unsigned) uniqueCount +{ + return NSCountMapTable (_contents_map); +} + +- (unsigned) occurrencesOfObject: anObject +{ + return (unsigned) NSMapGet (_contents_map, anObject); +} + + +// ENUMERATING; + +struct BagEnumState +{ + NSMapEnumerator me; + id object; + unsigned count; +}; + +#define ES ((struct BagEnumState *) *enumState) + +- nextObjectWithEnumState: (void**)enumState +{ + if (!(ES->count)) + if (!NSNextMapEnumeratorPair (&(ES->me), + (void**) &(ES->object), + (void**) &(ES->count))) + return NO_OBJECT; + ES->count--; + return ES->object; +} + +- (void*) newEnumState +{ + /* init for start of enumeration. */ + void *vp; + void **enumState = &vp; + OBJC_MALLOC(*enumState, struct BagEnumState, 1); + ES->me = NSEnumerateMapTable (_contents_map); + ES->object = nil; + ES->count = 0; + return vp; +} + +- (void) freeEnumState: (void**)enumState +{ + if (*enumState) + OBJC_FREE(*enumState); +} + +@end + + diff --git a/Old/BinaryCStream.h b/Old/BinaryCStream.h new file mode 100644 index 000000000..5ad7db50c --- /dev/null +++ b/Old/BinaryCStream.h @@ -0,0 +1,42 @@ +/* Interface for GNU Objective-C binary stream object for use serializing + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Written: Jan 1996 + + 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 __BinaryCStream_h_GNUSTEP_BASE_INCLUDE +#define __BinaryCStream_h_GNUSTEP_BASE_INCLUDE + +#include +#include + +@interface BinaryCStream : CStream +{ + unsigned char _sizeof_long; + unsigned char _sizeof_int; + unsigned char _sizeof_short; + unsigned char _sizeof_char; +} + ++ setDebugging: (BOOL)f; + +@end + +#endif /* __BinaryCStream_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/BinaryCStream.m b/Old/BinaryCStream.m new file mode 100644 index 000000000..f4d746459 --- /dev/null +++ b/Old/BinaryCStream.m @@ -0,0 +1,646 @@ +/* Implementation of GNU Objective-C binary stream object for use serializing + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Written: Jan 1996 + + 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if HAVE_VALUES_H +#include // This gets BITSPERBYTE on Solaris +#endif + +#define PRE_SIZEOF_PREFIX_FORMAT_VERSION 0 +#define CURRENT_FORMAT_VERSION ((((GNUSTEP_BASE_MAJOR_VERSION * 100) + \ + GNUSTEP_BASE_MINOR_VERSION) * 100) + GNUSTEP_BASE_SUBMINOR_VERSION) +#define DEFAULT_FORMAT_VERSION CURRENT_FORMAT_VERSION + +#define ROUND(V, A) \ + ({ typeof(V) __v=(V); typeof(A) __a=(A); \ + __a*((__v+__a-1)/__a); }) + +/* The number of bytes used to encode the length of a _C_CHARPTR + string that is encoded. */ +#define NUM_BYTES_STRING_LENGTH 4 + +/* The value by which we multiply a float or double in order to bring + mantissa digits to the left-hand-side of the decimal point, so that + we can extract them by assigning the float or double to an int. */ +#if !defined(BITSPERBYTE) && defined(NeXT) +#include +#define BITSPERBYTE BYTE_SIZE +#elif !defined(BITSPERBYTE) +#define BITSPERBYTE 8 /* a safe guess? */ +#endif +#define FLOAT_FACTOR ((double)(1 << ((sizeof(int)*BITSPERBYTE)-2))) + +@implementation BinaryCStream + ++ (void) initialize +{ + if (self == [BinaryCStream class]) + /* Make sure that we don't overrun memory when reading _C_CHARPTR. */ + NSAssert (sizeof(unsigned) >= NUM_BYTES_STRING_LENGTH, + @"_C_CHARPTR overruns memory"); +} + + +/* For debugging */ + +static int debug_binary_coder = 0; + ++ setDebugging: (BOOL)f +{ + debug_binary_coder = f; + return self; +} + ++ debugStderrCoder +{ + static id c = nil; + + if (!c) + c = [[TextCStream alloc] + initForWritingToStream: [StdioStream standardError]]; + return c; +} + +/* This is the designated initializer for reading. */ +- _initForReadingFromPostSignatureStream: (id )s + withFormatVersion: (int)version +{ + [super _initForReadingFromPostSignatureStream: s + withFormatVersion: version]; + if (version > PRE_SIZEOF_PREFIX_FORMAT_VERSION) + { + /* Read the C-type sizes to expect. */ + [s readByte: &_sizeof_long]; + [s readByte: &_sizeof_int]; + [s readByte: &_sizeof_short]; + [s readByte: &_sizeof_char]; + } + return self; +} + +/* This is a designated initializer for writing. */ +- initForWritingToStream: (id ) s + withFormatVersion: (int)version +{ + [super initForWritingToStream: s + withFormatVersion: version]; + if (version > PRE_SIZEOF_PREFIX_FORMAT_VERSION) + { + [s writeByte: sizeof (long)]; + [s writeByte: sizeof (int)]; + [s writeByte: sizeof (short)]; + [s writeByte: sizeof (char)]; + } + return self; +} + + +/* Encoding/decoding C values */ + +- (void) encodeValueOfCType: (const char*)type + at: (const void*)d + withName: (NSString*) name +{ + if (!type) + [NSException raise:NSInvalidArgumentException format:@"type is NULL"]; + + /* Make sure we're not being asked to encode an "ObjC" type. */ + NSAssert(*type != '@', @"tried to encode an \"ObjC\" type"); + NSAssert(*type != '^', @"tried to encode an \"ObjC\" type"); + NSAssert(*type != ':', @"tried to encode an \"ObjC\" type"); + + if (debug_binary_coder) + { + [[[self class] debugStderrCoder] + encodeValueOfCType: type + at: d + withName: name]; + } + + [stream writeByte: *type]; + +#define WRITE_SIGNED_TYPE0(_PTR, _TYPE, _CONV_FUNC) \ + { \ + _TYPE tmp; \ + char buffer[1+sizeof(_TYPE)]; \ + buffer[0] = sizeof (_TYPE); \ + if (*(_TYPE*)_PTR < 0) \ + { \ + buffer[0] |= 0x80; \ + tmp = _CONV_FUNC (- *(_TYPE*)_PTR); \ + memcpy (buffer+1, &tmp, sizeof(_TYPE)); \ + } \ + else \ + { \ + tmp = _CONV_FUNC (*(_TYPE*)_PTR); \ + memcpy (buffer+1, &tmp, sizeof(_TYPE)); \ + } \ + [stream writeBytes: buffer length: 1+sizeof(_TYPE)]; \ + } + +#define WRITE_SIGNED_TYPE1(_PTR, _TYPE, _CONV_FUNC) \ + { \ + _TYPE tmp; \ + char buffer[sizeof(_TYPE)]; \ + if (*(_TYPE*)_PTR < 0) \ + { \ + tmp = _CONV_FUNC (- *(_TYPE*)_PTR); \ + memcpy (buffer, &tmp, sizeof(_TYPE)); \ + NSAssert(!(buffer[0] & 0x80), @"high bit set"); \ + buffer[0] |= 0x80; \ + } \ + else \ + { \ + tmp = _CONV_FUNC (*(_TYPE*)_PTR); \ + memcpy (buffer, &tmp, sizeof(_TYPE)); \ + } \ + [stream writeBytes: buffer length: sizeof(_TYPE)]; \ + } + +#define WRITE_SIGNED_TYPE(_PTR, _TYPE, _CONV_FUNC) \ + { \ + if (format_version == PRE_SIZEOF_PREFIX_FORMAT_VERSION) \ + WRITE_SIGNED_TYPE0 (_PTR, _TYPE, _CONV_FUNC) \ + else \ + WRITE_SIGNED_TYPE1 (_PTR, _TYPE, _CONV_FUNC) \ + } + +#define READ_SIGNED_TYPE0(_PTR, _TYPE, _CONV_FUNC) \ + { \ + char sign, size; \ + [stream readByte: &size]; \ + sign = size & 0x80; \ + size &= ~0x80; \ + { \ + char buffer[size]; \ + int read_size; \ + read_size = [stream readBytes: buffer length: size]; \ + NSAssert (read_size == size, @"expected more input"); \ + NSAssert (size == sizeof(_TYPE), @"inconsistent size");\ + *(unsigned _TYPE*)_PTR = \ + _CONV_FUNC (*(unsigned _TYPE*)buffer); \ + if (sign) \ + *(_TYPE*)_PTR = - *(_TYPE*)_PTR; \ + } \ + } + +#define READ_SIGNED_TYPE1(_PTR, _TYPE, _CONV_FUNC) \ + { \ + int size = _sizeof_ ## _TYPE; \ + char buffer[size]; \ + int read_size; \ + int sign; \ + read_size = [stream readBytes: buffer length: size]; \ + NSAssert (read_size == size, @"expected more input"); \ + /* xxx Remove this next requirement eventually */ \ + NSAssert (size == sizeof(_TYPE), @"inconsistent size"); \ + sign = buffer[0] & 0x80; \ + buffer[0] &= ~0x80; \ + *(unsigned _TYPE*)_PTR = \ + _CONV_FUNC (*(unsigned _TYPE*)buffer); \ + if (sign) \ + *(_TYPE*)_PTR = - *(_TYPE*)_PTR; \ + } + +#define READ_SIGNED_TYPE(_PTR, _TYPE, _CONV_FUNC) \ + { \ + if (format_version == PRE_SIZEOF_PREFIX_FORMAT_VERSION) \ + READ_SIGNED_TYPE0 (_PTR, _TYPE, _CONV_FUNC) \ + else \ + READ_SIGNED_TYPE1 (_PTR, _TYPE, _CONV_FUNC) \ + } + +/* Reading and writing unsigned scalar types. */ + +#define WRITE_UNSIGNED_TYPE0(_PTR, _TYPE, _CONV_FUNC) \ + { \ + _TYPE tmp; \ + char buffer[1+sizeof(_TYPE)]; \ + buffer[0] = sizeof (_TYPE); \ + tmp = _CONV_FUNC (*(_TYPE*)_PTR); \ + memcpy (buffer+1, &tmp, sizeof(_TYPE)); \ + [stream writeBytes: buffer length: (1+sizeof(_TYPE))]; \ + } + +#define WRITE_UNSIGNED_TYPE1(_PTR, _TYPE, _CONV_FUNC) \ + { \ + unsigned _TYPE tmp; \ + char buffer[sizeof(unsigned _TYPE)]; \ + tmp = _CONV_FUNC (*(unsigned _TYPE*)_PTR); \ + memcpy (buffer, &tmp, sizeof(unsigned _TYPE)); \ + [stream writeBytes: buffer length: (sizeof(unsigned _TYPE))]; \ + } + +#define WRITE_UNSIGNED_TYPE(_PTR, _TYPE, _CONV_FUNC) \ + { \ + if (format_version == PRE_SIZEOF_PREFIX_FORMAT_VERSION) \ + WRITE_UNSIGNED_TYPE0 (_PTR, _TYPE, _CONV_FUNC) \ + else \ + WRITE_UNSIGNED_TYPE1 (_PTR, _TYPE, _CONV_FUNC) \ + } + +#define READ_UNSIGNED_TYPE0(_PTR, _TYPE, _CONV_FUNC) \ + { \ + char size; \ + [stream readByte: &size]; \ + { \ + char buffer[size]; \ + int read_size; \ + read_size = [stream readBytes: buffer length: size]; \ + NSAssert (read_size == size, @"expected more input"); \ + NSAssert (size == sizeof(_TYPE), @"inconsistent size");\ + *(_TYPE*)_PTR = \ + _CONV_FUNC (*(_TYPE*)buffer); \ + } \ + } + +#define READ_UNSIGNED_TYPE1(_PTR, _TYPE, _CONV_FUNC) \ + { \ + int size = _sizeof_ ## _TYPE; \ + char buffer[size]; \ + int read_size; \ + read_size = [stream readBytes: buffer length: size]; \ + NSAssert (read_size == size, @"expected more input"); \ + /* xxx Remove this next requirement eventually */ \ + NSAssert (size == sizeof(_TYPE), @"inconsistent size"); \ + *(unsigned _TYPE*)_PTR = \ + _CONV_FUNC (*(unsigned _TYPE*)buffer); \ + } + +#define READ_UNSIGNED_TYPE(_PTR, _TYPE, _CONV_FUNC) \ + { \ + if (format_version == PRE_SIZEOF_PREFIX_FORMAT_VERSION) \ + READ_UNSIGNED_TYPE0 (_PTR, _TYPE, _CONV_FUNC) \ + else \ + READ_UNSIGNED_TYPE1 (_PTR, _TYPE, _CONV_FUNC) \ + } + + switch (*type) + { + case _C_CHARPTR: + { + unsigned length = strlen (*(char**)d); + unsigned nlength; + nlength = NSSwapHostIntToBig (length); + [stream writeBytes: &nlength + length: NUM_BYTES_STRING_LENGTH]; + [stream writeBytes: *(char**)d + length: length]; + break; + } + + case _C_CHR: + case _C_UCHR: + [stream writeByte: *(unsigned char*)d]; + break; + +/* Reading and writing signed scalar types. */ + + case _C_SHT: + WRITE_SIGNED_TYPE (d, short, NSSwapHostShortToBig); + break; + case _C_USHT: + WRITE_UNSIGNED_TYPE (d, short, NSSwapHostShortToBig); + break; + + case _C_INT: + WRITE_SIGNED_TYPE (d, int, NSSwapHostIntToBig); + break; + case _C_UINT: + WRITE_UNSIGNED_TYPE (d, int, NSSwapHostIntToBig); + break; + + case _C_LNG: + WRITE_SIGNED_TYPE (d, long, NSSwapHostLongToBig); + break; + case _C_ULNG: + WRITE_UNSIGNED_TYPE (d, long, NSSwapHostLongToBig); + break; + + /* xxx The handling of floats and doubles could be improved. + e.g. I should account for varying sizeof(int) vs sizeof(double). */ + + case _C_FLT: + { + float fvalue; + double value; + int exponent, mantissa; + short exponent_encoded; + + memcpy (&fvalue, d, sizeof (float)); + value = fvalue; + /* Get the exponent */ + value = frexp (value, &exponent); + exponent_encoded = exponent; + NSParameterAssert (exponent_encoded == exponent); + /* Get the mantissa. */ + value *= FLOAT_FACTOR; + mantissa = value; + NSAssert (value - mantissa == 0, + @"mantissa and value should be the same"); + /* Encode the value as its two integer components. */ + WRITE_SIGNED_TYPE (&exponent_encoded, short, NSSwapHostShortToBig); + WRITE_SIGNED_TYPE (&mantissa, int, NSSwapHostIntToBig); + break; + } + + case _C_DBL: + { + double value; + int exponent, mantissa1, mantissa2; + short exponent_encoded; + + memcpy (&value, d, sizeof (double)); + /* Get the exponent */ + value = frexp (value, &exponent); + exponent_encoded = exponent; + NSParameterAssert (exponent_encoded == exponent); + /* Get the first part of the mantissa. */ + value *= FLOAT_FACTOR; + mantissa1 = value; + value -= mantissa1; + value *= FLOAT_FACTOR; + mantissa2 = value; + NSAssert (value - mantissa2 == 0, + @"mantissa2 and value should be the same"); + /* Encode the value as its three integer components. */ + WRITE_SIGNED_TYPE (&exponent_encoded, short, NSSwapHostShortToBig); + WRITE_SIGNED_TYPE (&mantissa1, int, NSSwapHostIntToBig); + WRITE_SIGNED_TYPE (&mantissa2, int, NSSwapHostIntToBig); + break; + } + + case _C_ARY_B: + { + int len = atoi (type+1); /* xxx why +1 ? */ + int offset; + + while (isdigit(*++type)); + offset = objc_sizeof_type(type); + [self encodeName:name]; + [self encodeIndent]; + while (len-- > 0) + { + /* Change this so we don't re-write type info every time. */ + /* xxx We should be able to encode arrays "ObjC" types also! */ + [self encodeValueOfCType:type + at:d + withName:@"array component"]; + ((char*)d) += offset; + } + [self encodeUnindent]; + break; + } + case _C_STRUCT_B: + { + int acc_size = 0; + int align; + + while (*type != _C_STRUCT_E && *type++ != '='); /* skip "=" */ + [self encodeName:name]; + [self encodeIndent]; + while (*type != _C_STRUCT_E) + { + align = objc_alignof_type (type); /* pad to alignment */ + acc_size = ROUND (acc_size, align); + /* xxx We should be able to encode structs "ObjC" types also! */ + [self encodeValueOfCType:type + at:((char*)d)+acc_size + withName:@"structure component"]; + acc_size += objc_sizeof_type (type); /* add component size */ + type = objc_skip_typespec (type); /* skip component */ + } + [self encodeUnindent]; + break; + } + default: + [NSException raise: NSGenericException + format: @"Unrecognized type %s", type]; + } +} + +- (void) decodeValueOfCType: (const char*)type + at: (void*)d + withName: (NSString* *)namePtr +{ + char encoded_type; + + if (!type) + [NSException raise:NSInvalidArgumentException format:@"type is NULL"]; + + NSAssert(*type != '@', @"tried to decode an \"ObjC\" type"); + NSAssert(*type != '^', @"tried to decode an \"ObjC\" type"); + NSAssert(*type != ':', @"tried to decode an \"ObjC\" type"); + + [stream readByte: &encoded_type]; + if (encoded_type != *type + && !((encoded_type=='c' || encoded_type=='C') + && (*type=='c' || *type=='C'))) + [NSException raise: NSGenericException + format: @"Expected type \"%c\", got type \"%c\"", + *type, encoded_type]; + + switch (encoded_type) + { + case _C_CHARPTR: + { + unsigned length; + unsigned read_count; + read_count = [stream readBytes: &length + length: NUM_BYTES_STRING_LENGTH]; + NSAssert2 (read_count == NUM_BYTES_STRING_LENGTH, + @"expected %d bytes of input, got %d", + NUM_BYTES_STRING_LENGTH,read_count); + length = NSSwapBigIntToHost (length); + OBJC_MALLOC (*(char**)d, char, length+1); + read_count = [stream readBytes: *(char**)d + length: length]; + NSAssert2 (read_count == length, + @"expected %d bytes of input, got %d",length,read_count); + (*(char**)d)[length] = '\0'; + /* Autorelease the newly malloc'ed pointer? Grep for (*objc_free) + to see the places the may have to be changed + [NSData dataWithBytesNoCopy: *(void**)d length: length+1]; */ + break; + } + + case _C_CHR: + case _C_UCHR: + [stream readByte: (unsigned char*)d]; + break; + + case _C_SHT: + READ_SIGNED_TYPE (d, short, NSSwapBigShortToHost); + break; + case _C_USHT: + READ_UNSIGNED_TYPE (d, short, NSSwapBigShortToHost); + break; + + case _C_INT: + READ_SIGNED_TYPE (d, int, NSSwapBigIntToHost); + break; + case _C_UINT: + READ_UNSIGNED_TYPE (d, int, NSSwapBigIntToHost); + break; + + case _C_LNG: + READ_SIGNED_TYPE (d, long, NSSwapBigLongToHost); + break; + case _C_ULNG: + READ_UNSIGNED_TYPE (d, long, NSSwapBigLongToHost); + break; + + case _C_FLT: + { + short exponent; + int mantissa; + double value; + float fvalue; + + /* Decode the exponent and mantissa. */ + READ_SIGNED_TYPE (&exponent, short, NSSwapBigShortToHost); + READ_SIGNED_TYPE (&mantissa, int, NSSwapBigIntToHost); + /* Assemble them into a double */ + value = mantissa / FLOAT_FACTOR; + value = ldexp (value, exponent); + /* Put the double into the requested memory location as a float */ + fvalue = value; + memcpy (d, &fvalue, sizeof (float)); + break; + } + + case _C_DBL: + { + short exponent; + int mantissa1, mantissa2; + double value; + + /* Decode the exponent and the two pieces of the mantissa. */ + READ_SIGNED_TYPE (&exponent, short, NSSwapBigShortToHost); + READ_SIGNED_TYPE (&mantissa1, int, NSSwapBigIntToHost); + READ_SIGNED_TYPE (&mantissa2, int, NSSwapBigIntToHost); + /* Assemble them into a double */ + value = ((mantissa2 / FLOAT_FACTOR) + mantissa1) / FLOAT_FACTOR; + value = ldexp (value, exponent); + /* Put the double into the requested memory location. */ + memcpy (d, &value, sizeof (double)); + break; + } + + case _C_ARY_B: + { + /* xxx Do we need to allocate space, just like _C_CHARPTR ? */ + int len = atoi(type+1); + int offset; + [self decodeName:namePtr]; + [self decodeIndent]; + while (isdigit(*++type)); + offset = objc_sizeof_type(type); + while (len-- > 0) + { + [self decodeValueOfCType:type + at:d + withName:namePtr]; + ((char*)d) += offset; + } + [self decodeUnindent]; + break; + } + case _C_STRUCT_B: + { + /* xxx Do we need to allocate space just like char* ? No. */ + int acc_size = 0; + int align; + const char *save_type = type; + + while (*type != _C_STRUCT_E && *type++ != '='); /* skip "=" */ + [self decodeName:namePtr]; + [self decodeIndent]; /* xxx insert [self decodeName:] */ + while (*type != _C_STRUCT_E) + { + align = objc_alignof_type (type); /* pad to alignment */ + acc_size = ROUND (acc_size, align); + [self decodeValueOfCType:type + at:((char*)d)+acc_size + withName:namePtr]; + acc_size += objc_sizeof_type (type); /* add component size */ + type = objc_skip_typespec (type); /* skip component */ + } + type = save_type; + [self decodeUnindent]; + break; + } + default: + [NSException raise: NSGenericException + format: @"Unrecognized Type %s", type]; + } + + if (debug_binary_coder) + { + [[[self class] debugStderrCoder] + encodeValueOfCType:type + at:d + withName:@"decoding unnamed"]; + } +} + + +/* Returning default format version. */ + ++ (int) defaultFormatVersion +{ + return DEFAULT_FORMAT_VERSION; +} + + +/* Encoding and decoding names. */ + +- (void) encodeName: (NSString*) name +{ + if (debug_binary_coder) + [[[self class] debugStderrCoder] + encodeName:name]; +} + +- (void) decodeName: (NSString* *)n +{ +#if 1 + if (n) + *n = nil; +#else + if (n) + *n = [[[NSString alloc] init] autorelease]; +#endif +} + +@end + diff --git a/Old/BinaryTree.h b/Old/BinaryTree.h new file mode 100644 index 000000000..7826ece78 --- /dev/null +++ b/Old/BinaryTree.h @@ -0,0 +1,76 @@ +/* Interface for Objective-C BinaryTree collection object + Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: May 1993 + + 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. +*/ + +/* + Binary Tree. + Base class for smarter binary trees. +*/ + +#ifndef __BinaryTree_h_GNUSTEP_BASE_INCLUDE +#define __BinaryTree_h_GNUSTEP_BASE_INCLUDE + +#include + +/* The protocol defines the interface to an object + that may be an element in a BinaryTree. +*/ +@protocol BinaryTreeComprising +- leftNode; +- rightNode; +- parentNode; +- (void) setLeftNode: (id )aNode; +- (void) setRightNode: (id )aNode; +- (void) setParentNode: (id )aNode; +- binaryTree; +- (void) setBinaryTree: anObject; +@end + +#define NODE_IS_RIGHTCHILD(NODE) (NODE == [[NODE parentNode] rightNode]) +#define NODE_IS_LEFTCHILD(NODE) (NODE == [[NODE parentNode] leftNode]) + +@interface BinaryTree : IndexedCollection +{ + unsigned int _count; + id _contents_root; +} + +- nilNode; +- rootNode; + +- leftmostNodeFromNode: aNode; +- rightmostNodeFromNode: aNode; + +- (unsigned) depthOfNode: aNode; +- (unsigned) heightOfNode: aNode; + +- (unsigned) nodeCountUnderNode: aNode; + +- leftRotateAroundNode: aNode; +- rightRotateAroundNode: aNode; + +- binaryTreePrintForDebugger; + +@end + + +#endif /* __BinaryTree_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/BinaryTree.m b/Old/BinaryTree.m new file mode 100644 index 000000000..dbb0319e2 --- /dev/null +++ b/Old/BinaryTree.m @@ -0,0 +1,607 @@ +/* Implementation for Objective-C BinaryTree collection object + Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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. +*/ + +#include +#include +#include +#include +#include + +/* the sentinal */ +static id nilBinaryTreeNode; + +@implementation BinaryTree + ++ (void) initialize +{ + if (self == [BinaryTree class]) + { + nilBinaryTreeNode = [[BinaryTreeNode alloc] init]; + } +} + +/* This is the designated initializer of this class */ +- init +{ + _count = 0; + _contents_root = [self nilNode]; + return self; +} + +/* Archiving must mimic the above designated initializer */ + +/* xxx See Collection _decodeContentsWithCoder:. + We shouldn't do an -addElement. finishEncodingInterconnectedObjects + should take care of all that. */ + +- _initCollectionWithCoder: aCoder +{ + [self notImplemented:_cmd]; + [super _initCollectionWithCoder:aCoder]; + _count = 0; + _contents_root = [self nilNode]; + return self; +} + +- (void) _encodeContentsWithCoder: (id )aCoder +{ + [aCoder startEncodingInterconnectedObjects]; + [super _encodeContentsWithCoder:aCoder]; + [aCoder finishEncodingInterconnectedObjects]; +} + +- (void) _decodeContentsWithCoder: (id )aCoder +{ + [aCoder startDecodingInterconnectedObjects]; + [super _decodeContentsWithCoder:aCoder]; + [aCoder finishDecodingInterconnectedObjects]; +} + +/* Empty copy must empty an allocCopy'ed version of self */ +- emptyCopy +{ + BinaryTree *copy = [super emptyCopy]; + copy->_count = 0; + copy->_contents_root = [self nilNode]; + return copy; +} + +/* This must work without sending any messages to content objects */ +- (void) _empty +{ + _count = 0; + _contents_root = [self nilNode]; +} + +- nilNode +{ + return nilBinaryTreeNode; +} + +- rootNode +{ + return _contents_root; +} + +- leftmostNodeFromNode: aNode +{ + id left; + + if (aNode && aNode != [self nilNode]) + { + while ((left = [aNode leftNode]) != [self nilNode]) + aNode = left; + } + return aNode; +} + +- rightmostNodeFromNode: aNode +{ + id right; + + if (aNode && aNode != [self nilNode]) + while ((right = [aNode rightNode]) != [self nilNode]) + { + aNode = right; + } + return aNode; +} + +- firstObject +{ + return [self leftmostNodeFromNode: _contents_root]; +} + +- lastObject +{ + return [self rightmostNodeFromNode: _contents_root]; +} + +/* This is correct only if the tree is sorted. How to deal with this? */ +- maxObject +{ + return [self rightmostNodeFromNode: _contents_root]; +} + +/* This is correct only is the tree is sorted. How to deal with this? */ +- minObject +{ + return [self leftmostNodeFromNode: _contents_root]; +} + +- successorOfObject: anObject +{ + id tmp; + + /* Make sure we actually own the anObject. */ + NSAssert([anObject binaryTree] == self, NSInternalInconsistencyException); + + // here tmp is the right node; + if ((tmp = [anObject rightNode]) != [self nilNode]) + return [self leftmostNodeFromNode: tmp]; + // here tmp is the parent; + tmp = [anObject parentNode]; + while (tmp != [self nilNode] && anObject == [tmp rightNode]) + { + anObject = tmp; + tmp = [tmp parentNode]; + } + if (tmp == [self nilNode]) + return NO_OBJECT; + return tmp; +} + +// I should make sure that [_contents_root parentNode] == [self nilNode]; +// Perhaps I should make [_contents_root parentNode] == binaryTreeObj ??; + +- predecessorObject: anObject +{ + id tmp; + + /* Make sure we actually own the anObject. */ + NSAssert([anObject binaryTree] == self, NSInternalInconsistencyException); + + // here tmp is the left node; + if ((tmp = [anObject leftNode]) != [self nilNode]) + return [self rightmostNodeFromNode:tmp]; + // here tmp is the parent; + tmp = [anObject parentNode]; + while (tmp != [self nilNode] && anObject == [tmp leftNode]) + { + anObject = tmp; + tmp = [tmp parentNode]; + } + if (tmp == [self nilNode]) + return NO_OBJECT; + return tmp; +} + +/* This relies on [_contents_root parentNode] == [self nilNode] */ +- rootFromNode: aNode +{ + id parentNode; + + /* Make sure we actually own the aNode. */ + NSAssert([aNode binaryTree] == self, NSInternalInconsistencyException); + + while ((parentNode = [aNode parentNode]) != [self nilNode]) + aNode = parentNode; + return aNode; +} + +/* This relies on [_contents_root parentNode] == [self nilNode] */ +- (unsigned) depthOfNode: aNode +{ + unsigned count = 0; + + /* Make sure we actually own the aNode. */ + NSAssert([aNode binaryTree] == self, NSInternalInconsistencyException); + + if (aNode == nil || aNode == [self nilNode]) + [self error:"in %s, Can't find depth of nil node", sel_get_name(_cmd)]; + do + { + aNode = [aNode parentNode]; + count++; + } + while (aNode != [self nilNode]); + return count; +} + +- (unsigned) heightOfNode: aNode +{ + unsigned leftHeight, rightHeight; + id tmpNode; + + /* Make sure we actually own the aNode. */ + NSAssert([aNode binaryTree] == self, NSInternalInconsistencyException); + + if (aNode == nil || aNode == [self nilNode]) + { + [self error:"in %s, Can't find height of nil node", sel_get_name(_cmd)]; + return 0; + } + else + { + leftHeight = ((tmpNode = [aNode leftNode]) + ? + (1 + [self heightOfNode:tmpNode]) + : + 0); + rightHeight = ((tmpNode = [aNode rightNode]) + ? + (1 + [self heightOfNode:tmpNode]) + : + 0); + return MAX(leftHeight, rightHeight); + } +} + +- (unsigned) nodeCountUnderNode: aNode +{ + unsigned count = 0; + + /* Make sure we actually own the aNode. */ + NSAssert([aNode binaryTree] == self, NSInternalInconsistencyException); + + if ([aNode leftNode] != [self nilNode]) + count += 1 + [self nodeCountUnderNode:[aNode leftNode]]; + if ([aNode rightNode] != [self nilNode]) + count += 1 + [self nodeCountUnderNode:[aNode rightNode]]; + return count; +} + +- leftRotateAroundNode: aNode +{ + id y; + + /* Make sure we actually own the aNode. */ + NSAssert([aNode binaryTree] == self, NSInternalInconsistencyException); + + y = [aNode rightNode]; + if (y == [self nilNode]) + return self; + [aNode setRightNode:[y leftNode]]; + if ([y leftNode] != [self nilNode]) + [[y leftNode] setParentNode:aNode]; + [y setParentNode:[aNode parentNode]]; + if ([aNode parentNode] == [self nilNode]) + _contents_root = y; + else + { + if (NODE_IS_LEFTCHILD(aNode)) + [[aNode parentNode] setLeftNode:y]; + else + [[aNode parentNode] setRightNode:y]; + } + [y setLeftNode:aNode]; + [aNode setParentNode:y]; + return self; +} + +- rightRotateAroundNode: aNode +{ + id y; + + /* Make sure we actually own the aNode. */ + NSAssert([aNode binaryTree] == self, NSInternalInconsistencyException); + + y = [aNode leftNode]; + if (y == [self nilNode]) + return self; + [aNode setLeftNode:[y rightNode]]; + if ([y rightNode] != [self nilNode]) + [[y rightNode] setParentNode:aNode]; + [y setParentNode:[aNode parentNode]]; + if ([aNode parentNode] == [self nilNode]) + _contents_root = y; + else + { + if (NODE_IS_RIGHTCHILD(aNode)) + [[aNode parentNode] setRightNode:y]; + else + [[aNode parentNode] setLeftNode:y]; + } + [y setRightNode:aNode]; + [aNode setParentNode:y]; + return self; +} + +- objectAtIndex: (unsigned)index +{ + id ret; + + CHECK_INDEX_RANGE_ERROR(index, _count); + ret = [self firstObject]; + // Not very efficient; Should be rewritten; + while (index--) + ret = [self successorOfObject: ret]; + return ret; +} + +- (void) sortAddObject: newObject +{ + id theParent, tmpChild; + + /* Make sure no one else already owns the newObject. */ + NSAssert([newObject binaryTree] == NO_OBJECT, NSInternalInconsistencyException); + + /* Claim ownership of the newObject. */ + [newObject retain]; + [newObject setBinaryTree: self]; + + [newObject setLeftNode:[self nilNode]]; + [newObject setRightNode:[self nilNode]]; + theParent = [self nilNode]; + tmpChild = _contents_root; + while (tmpChild != [self nilNode]) + { + theParent = tmpChild; + if ([newObject compare: theParent] < 0) + tmpChild = [tmpChild leftNode]; + else + tmpChild = [tmpChild rightNode]; + } + [newObject setParentNode:theParent]; + if (theParent == [self nilNode]) + _contents_root = newObject; + else + { + if ([newObject compare: theParent] < 0) + [theParent setLeftNode:newObject]; + else + [theParent setRightNode:newObject]; + } + _count++; +} + +- (void) addObject: newObject +{ + // By default insert in sorted order. + [self sortAddObject: newObject]; +} + +- (void) removeObject: oldObject +{ + id x, y; + + /* Make sure we actually own the aNode. */ + NSAssert([oldObject binaryTree] == self, NSInternalInconsistencyException); + + /* Extract the oldObject and sew up the cut. */ + if ([oldObject leftNode] == [self nilNode] + || [oldObject rightNode] == [self nilNode]) + y = oldObject; + else + y = [self successorOfObject: oldObject]; + + if ([y leftNode] != [self nilNode]) + x = [y leftNode]; + else + x = [y rightNode]; + + if (x != [self nilNode]) + [x setParentNode: [y parentNode]]; + + if ([y parentNode] == [self nilNode]) + _contents_root = x; + else + { + if (y == [[y parentNode] leftNode]) + [[y parentNode] setLeftNode: x]; + else + [[y parentNode] setRightNode: x]; + } + + if (y != oldObject) + { + /* put y in the place of oldObject */ + [y setParentNode: [oldObject parentNode]]; + [y setLeftNode: [oldObject leftNode]]; + [y setRightNode: [oldObject rightNode]]; + if (oldObject == [[oldObject parentNode] leftNode]) + [[oldObject parentNode] setLeftNode: y]; + else + [[oldObject parentNode] setRightNode: y]; + [[oldObject leftNode] setParentNode: y]; + [[oldObject rightNode] setParentNode: y]; + } + _count--; + + /* Release ownership of the object. */ +#if 0 + [oldObject setRightNode: [self nilNode]]; + [oldObject setLeftNode: [self nilNode]]; + [oldObject setParentNode: [self nilNode]]; +#else + [oldObject setLeftNode: NO_OBJECT]; + [oldObject setRightNode: NO_OBJECT]; + [oldObject setParentNode: NO_OBJECT]; +#endif + [oldObject setBinaryTree: NO_OBJECT]; + [oldObject release]; +} + + +// ENUMERATING; + +- nextObjectWithEnumState: (void**)enumState +{ + if (!(*enumState)) + *enumState = [self leftmostNodeFromNode:_contents_root]; + else + *enumState = [self successorOfObject:*enumState]; + return (id) *enumState; +} + +- prevObjectWithEnumState: (void**)enumState +{ + if (!(*enumState)) + *enumState = [self rightmostNodeFromNode:_contents_root]; + else + *enumState = [self predecessorObject:*enumState]; + return (id) *enumState; +} + +- (unsigned) count +{ + return _count; +} + + +/* replace this with something better eventually */ +- _tmpPrintFromNode: aNode indent: (int)count +{ + printf("%-*s", count, ""); + printf("%s\n", [[aNode description] cString]); + printf("%-*s.", count, ""); + if ([aNode leftNode] != [self nilNode]) + [self _tmpPrintFromNode:[aNode leftNode] indent:count+2]; + else + printf("\n"); + printf("%-*s.", count, ""); + if ([aNode rightNode] != [self nilNode]) + [self _tmpPrintFromNode:[aNode rightNode] indent:count+2]; + else + printf("\n"); + return self; +} + +- binaryTreePrintForDebugger +{ + [self _tmpPrintFromNode:_contents_root indent:0]; + return self; +} + +@end + + + +/* These methods removed because they belong to an + OrderedCollection implementation, not an IndexedCollection + implementation. */ + +#if 0 +// NOTE: This gives you the power to put elements in unsorted order; +- insertObject: newObject before: oldObject +{ + id tmp; + + /* Make sure no one else already owns the newObject. */ + NSAssert([newObject linkedList] == NO_OBJECT, NSInternalInconsistencyException); + + /* Claim ownership of the newObject. */ + [newObject retain]; + [newObject setBinaryTree: self]; + + [newObject setRightNode:[self nilNode]]; + [newObject setLeftNode:[self nilNode]]; + if ((tmp = [oldObject leftNode]) != [self nilNode]) + { + [(tmp = [self rightmostNodeFromNode:tmp]) setRightNode:newObject]; + [newObject setParentNode:tmp]; + } + else if (newObject != [self nilNode]) + { + [oldObject setLeftNode:newObject]; + [newObject setParentNode:oldObject]; + } + else + { + _contents_root = newObject; + [newObject setParentNode:[self nilNode]]; + } + _count++; + RETAIN_ELT(newObject); + return self; +} + +// NOTE: This gives you the power to put elements in unsorted order; +- insertObject: newObject after: oldObject +{ + id tmp; + + /* Make sure no one else already owns the newObject. */ + NSAssert([newObject linkedList] == NO_OBJECT, NSInternalInconsistencyException); + + /* Claim ownership of the newObject. */ + [newObject retain]; + [newObject setBinaryTree: self]; + + [newObject setRightNode:[self nilNode]]; + [newObject setLeftNode:[self nilNode]]; + if ((tmp = [oldObject rightNode]) != [self nilNode]) + { + [(tmp = [self leftmostNodeFromNode:tmp]) setLeftNode:newObject]; + [newObject setParentNode:tmp]; + } + else if (newObject != [self nilNode]) + { + [oldObject setRightNode:newObject]; + [newObject setParentNode:oldObject]; + } + else + { + _contents_root = newObject; + [newObject setParentNode:[self nilNode]]; + } + _count++; + RETAIN_ELT(newObject); + return self; +} + +// NOTE: This gives you the power to put elements in unsorted order; +- insertObject: newObject atIndex: (unsigned)index +{ + CHECK_INDEX_RANGE_ERROR(index, _count+1); + + if (index == _count) + [self appendObject:newObject]; + else + [self insertObject:newObject before:[self ObjectAtIndex:index]]; + return self; +} + +// NOTE: This gives you the power to put elements in unsorted order; +- appendObject: newObject +{ + if (_count == 0) + { + /* Make sure no one else already owns the newObject. */ + NSAssert([newObject linkedList] == NO_OBJECT, NSInternalInconsistencyException); + + /* Claim ownership of the newObject. */ + [newObject retain]; + [newObject setBinaryTree: self]; + + _contents_root = newObject; + _count = 1; + [newObject setLeftNode:[self nilNode]]; + [newObject setRightNode:[self nilNode]]; + [newObject setParentNode:[self nilNode]]; + } + else + [self insertObject:newObject after:[self lastObject]]; + return self; +} +#endif diff --git a/Old/BinaryTreeNode.h b/Old/BinaryTreeNode.h new file mode 100644 index 000000000..542c841da --- /dev/null +++ b/Old/BinaryTreeNode.h @@ -0,0 +1,40 @@ +/* Interface for Objective-C BinaryTreeNode object + Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: May 1993 + + 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 __BinaryTreeNode_h_GNUSTEP_BASE_INCLUDE +#define __BinaryTreeNode_h_GNUSTEP_BASE_INCLUDE + +#include +#include + +@interface BinaryTreeNode : NSObject +{ + id _left; + id _right; + id _parent; + id _binary_tree; +} +@end + + +#endif /* __BinaryTreeNode_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/BinaryTreeNode.m b/Old/BinaryTreeNode.m new file mode 100644 index 000000000..b3fe2273a --- /dev/null +++ b/Old/BinaryTreeNode.m @@ -0,0 +1,104 @@ +/* Implementation for Objective-C BinaryTreeNode object + Copyright (C) 1993,1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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. +*/ + +#include +#include +#include + +@implementation BinaryTreeNode + ++ (void) initialize +{ + if (self == [BinaryTreeNode class]) + [self setVersion:0]; /* beta release */ +} + +- init +{ + [super init]; + _left = _right = _parent = nil; + return self; +} + +- (void) encodeWithCoder: aCoder +{ + [super encodeWithCoder:(id)aCoder]; + [aCoder encodeObjectReference:_right withName:@"Right BinaryTree Node"]; + [aCoder encodeObjectReference:_left withName:@"Left BinaryTree Node"]; + [aCoder encodeObjectReference:_parent withName:@"Parent BinaryTree Node"]; + [aCoder encodeObjectReference:_binary_tree + withName:@"BinaryTree"]; +} + +- initWithCoder: aCoder +{ + [super initWithCoder:aCoder]; + [aCoder decodeObjectAt:&_right withName:NULL]; + [aCoder decodeObjectAt:&_left withName:NULL]; + [aCoder decodeObjectAt:&_parent withName:NULL]; + [aCoder decodeObjectAt:&_binary_tree withName:NULL]; + return self; +} + +- leftNode +{ + return _left; +} + +- rightNode +{ + return _right; +} + +- parentNode +{ + return _parent; +} + +- (void) setLeftNode: aNode +{ + _left = aNode; +} + +- (void) setRightNode: aNode +{ + _right = aNode; +} + +- (void) setParentNode: aNode +{ + _parent = aNode; +} + +- binaryTree +{ + return _binary_tree; +} + +- (void) setBinaryTree: anObject +{ + _binary_tree = anObject; +} + +@end + diff --git a/Old/CStream.h b/Old/CStream.h new file mode 100644 index 000000000..2da77918a --- /dev/null +++ b/Old/CStream.h @@ -0,0 +1,62 @@ +/* Interface for GNU Objective-C stream object for use in archiving + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Written: Jan 1996 + + 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 __CStream_h_GNUSTEP_BASE_INCLUDE +#define __CStream_h_GNUSTEP_BASE_INCLUDE + +#include +#include + +@interface CStream : Stream +{ + Stream *stream; + int format_version; + int indentation; +} + +/* These are the standard ways to create a new CStream from a Stream + that is open for reading. + It reads the CStream signature at the beginning of the file, and + automatically creates the appropriate subclass of CStream with + the correct format version. */ ++ cStreamReadingFromFile: (NSString*) filename; ++ cStreamReadingFromStream: (id ) stream; + +/* These are standard ways to create a new CStream with a Stream + that is open for writing. */ +- initForWritingToFile: (NSString*) filename; +- initForWritingToStream: (id ) stream; + +- initForWritingToStream: (id ) s + withFormatVersion: (int)version; + ++ cStreamWritingToStream: (id ) stream; ++ cStreamWritingToFile: (NSString*) filename; + +/* This is the designated initializer for reading. Don't call it yourself. */ +- _initForReadingFromPostSignatureStream: (id )s + withFormatVersion: (int)version; + +@end + +#endif /* __CStream_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/CStream.m b/Old/CStream.m new file mode 100644 index 000000000..8420238b6 --- /dev/null +++ b/Old/CStream.m @@ -0,0 +1,287 @@ +/* Implementation of GNU Objective-C class for streaming C types and indentatn + Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: July 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. + */ + +#include +#include +#include +#include +#include +#include /* for SIGNATURE_FORMAT_STRING */ +#include + +id CStreamSignatureMalformedException = @"CStreamSignatureMalformedException"; +id CStreamSignatureMismatchException = @"CStreamSignatureMismatchException"; + +@implementation CStream + + +/* Encoding/decoding C values */ + +- (void) encodeValueOfCType: (const char*) type + at: (const void*) d + withName: (NSString*) name; +{ + [self subclassResponsibility:_cmd]; +} + +- (void) decodeValueOfCType: (const char*) type + at: (void*) d + withName: (NSString* *) namePtr; +{ + [self subclassResponsibility:_cmd]; +} + + +/* Signature methods. */ + +- (void) writeSignature +{ + /* Careful: the string should not contain newlines. */ + [stream writeFormat: SIGNATURE_FORMAT_STRING, + STRINGIFY(GNUSTEP_BASE_PACKAGE_NAME), + GNUSTEP_BASE_MAJOR_VERSION, + GNUSTEP_BASE_MINOR_VERSION, + GNUSTEP_BASE_SUBMINOR_VERSION, + object_get_class_name(self), + format_version]; +} + ++ (void) readSignatureFromStream: s + getClassname: (char *) name + formatVersion: (int*) version +{ + int got; + char package_name[64]; + int major_version; + int minor_version; + int subminor_version; + + got = [s readFormat: SIGNATURE_FORMAT_STRING, + &(package_name[0]), + &major_version, + &minor_version, + &subminor_version, + name, + version]; + if (got != 6) + [NSException raise:CStreamSignatureMalformedException + format: @"CStream found a malformed signature"]; +} + + +/* Initialization methods */ + +/* This is the hidden designated initializer. Do not call it yourself. */ +- _initWithStream: (id ) s + formatVersion: (int)version +{ + [super init]; + [s retain]; + stream = s; + format_version = version; + indentation = 0; + return self; +} + +/* This is the designated initializer for reading. */ +- _initForReadingFromPostSignatureStream: (id )s + withFormatVersion: (int)version +{ + [self _initWithStream: s + formatVersion: version]; + return self; +} + +- initForReadingFromStream: (id ) s + withFormatVersion: (int)version +{ + [self notImplemented: _cmd]; + /* xxx Why this condition? -mccallum */ + if ([stream streamPosition] != 0) + { + char name[128]; /* max class name length. */ + int version; + [[self class] readSignatureFromStream: stream + getClassname: name + formatVersion: &version]; + if (!strcmp(name, object_get_class_name(self)) + || version != format_version) + { + [NSException raise: CStreamSignatureMismatchException + format: @"CStream found a mismatched signature"]; + } + [self _initForReadingFromPostSignatureStream: s + withFormatVersion: version]; + } + return self; +} + ++ cStreamReadingFromStream: (id ) s +{ + char name[128]; /* Maximum class name length. */ + int version; + id new_cstream; + + [self readSignatureFromStream: s + getClassname: name + formatVersion: &version]; + new_cstream = [[objc_lookup_class(name) alloc] + _initForReadingFromPostSignatureStream: s + withFormatVersion: version]; + return [new_cstream autorelease]; +} + ++ cStreamReadingFromFile: (NSString*) filename +{ + return [self cStreamReadingFromStream: + [StdioStream streamWithFilename: filename fmode: "r"]]; +} + +/* This is a designated initializer for writing. */ +- initForWritingToStream: (id ) s + withFormatVersion: (int)version +{ + [self _initWithStream: s + formatVersion: version]; + [self writeSignature]; + return self; +} + +- initForWritingToStream: (id ) s +{ + return [self initForWritingToStream: s + withFormatVersion: [[self class] defaultFormatVersion]]; +} + +- initForWritingToFile: (NSString*) file +{ + return [self initForWritingToStream: + [StdioStream streamWithFilename: file fmode: "w"]]; +} + ++ cStreamWritingToStream: (id ) s +{ + return [[[self alloc] initForWritingToStream: s] + autorelease]; +} + ++ cStreamWritingToFile: (NSString*) filename; +{ + return [[[self alloc] initForWritingToFile: filename] + autorelease]; +} + + +/* Encoding/decoding indentation */ + +- (void) encodeWithName: (NSString*) name + valuesOfCTypes: (const char *) types, ... +{ + va_list ap; + + [self encodeName: name]; + va_start (ap, types); + while (*types) + { + [self encodeValueOfCType: types + at: va_arg(ap, void*) + withName: NULL]; + types = objc_skip_typespec (types); + } + va_end (ap); +} + +- (void) decodeWithName: (NSString* *)name + valuesOfCTypes: (const char *)types, ... +{ + va_list ap; + + [self decodeName: name]; + va_start (ap, types); + while (*types) + { + [self decodeValueOfCType: types + at: va_arg (ap, void*) + withName: NULL]; + types = objc_skip_typespec (types); + } + va_end (ap); +} + +- (void) encodeIndent +{ + /* Do nothing */ +} + +- (void) encodeUnindent +{ + /* Do nothing */ +} + +- (void) decodeIndent +{ + /* Do nothing */ +} + +- (void) decodeUnindent +{ + /* Do nothing */ +} + +- (void) encodeName: (NSString*) n +{ + /* Do nothing */ +} + +- (void) decodeName: (NSString* *) name +{ + /* Do nothing */ +} + + +/* Access to the underlying stream. */ + +- (id ) stream +{ + return stream; +} + + +/* Deallocation. */ + +- (void) dealloc +{ + [stream release]; + [super dealloc]; +} + + +/* Returning default format version. */ + ++ (int) defaultFormatVersion +{ + [self subclassResponsibility:_cmd]; + return 0; +} + +@end diff --git a/Old/CStreaming.h b/Old/CStreaming.h new file mode 100644 index 000000000..2e2b38cbc --- /dev/null +++ b/Old/CStreaming.h @@ -0,0 +1,59 @@ +/* Protocol for GNU Objective C byte streams that can code C types and indentn + Copyright (C) 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: April 1995 + + 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 __CStreaming_h__GNUSTEP_BASE_INCLUDE +#define __CStreaming_h__GNUSTEP_BASE_INCLUDE + +#include + +@protocol CStreaming + +- (void) encodeValueOfCType: (const char*) type + at: (const void*) d + withName: (NSString*) name; +- (void) decodeValueOfCType: (const char*) type + at: (void*) d + withName: (NSString* *) namePtr; + +- (void) encodeWithName: (NSString*) name + valuesOfCTypes: (const char *) types, ...; +- (void) decodeWithName: (NSString* *)name + valuesOfCTypes: (const char *)types, ...; + +- (void) encodeName: (NSString*) name; +- (void) decodeName: (NSString* *) name; + +- (void) encodeIndent; +- (void) decodeIndent; + +- (void) encodeUnindent; +- (void) decodeUnindent; + +- (id ) stream; + ++ (int) defaultFormatVersion; + +@end + +#endif /* __CStreaming_h__GNUSTEP_BASE_INCLUDE */ + diff --git a/Old/CircularArray.h b/Old/CircularArray.h new file mode 100644 index 000000000..ace57d70f --- /dev/null +++ b/Old/CircularArray.h @@ -0,0 +1,37 @@ +/* Interface for Objective-C CircularArray collection object + Copyright (C) 1993,1994 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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 __CircularArray_h_GNUSTEP_BASE_INCLUDE +#define __CircularArray_h_GNUSTEP_BASE_INCLUDE + +#include + +@interface CircularArray : Array +{ + @public + unsigned int _start_index; +} + +@end + +#endif /* __CircularArray_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/CircularArray.m b/Old/CircularArray.m new file mode 100644 index 000000000..9d104233e --- /dev/null +++ b/Old/CircularArray.m @@ -0,0 +1,197 @@ +/* Implementation for Objective-C CircularArray collection object + Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: May 1993 + + 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. +*/ + + +#include +#include +#include + +@implementation CircularArray + +/* This is the designated initializer of this class */ +- initWithCapacity: (unsigned)aCapacity +{ + [super initWithCapacity:aCapacity]; + _start_index = 0; + return self; +} + +/* Archiving must mimic the above designated initializer */ + +- _initCollectionWithCoder: coder +{ + [super _initCollectionWithCoder:coder]; + _start_index = 0; + return self; +} + +/* Empty copy must empty an allocCopy'ed version of self */ + +- emptyCopy +{ + CircularArray *copy = [super emptyCopy]; + copy->_start_index = 0; + return copy; +} + +- (void) empty +{ + [super empty]; + _start_index = 0; +} + +/* This is the only method that changes the value of the instance + variable _capacity, except for "-initWithCapacity:" */ + +- (void) setCapacity: (unsigned)newCapacity +{ + id *new_contents; + int i; + + if (newCapacity > _count) { + /* This could be more efficient */ + OBJC_MALLOC(new_contents, id, newCapacity); + for (i = 0; i < _count; i++) + new_contents[i] = _contents_array[CIRCULAR_TO_BASIC(i)]; + OBJC_FREE(_contents_array); + _contents_array = new_contents; + _start_index = 0; + _capacity = newCapacity; + } +} + +- (void) removeObjectAtIndex: (unsigned)index +{ + unsigned basicIndex; + + CHECK_INDEX_RANGE_ERROR(index, _count); + basicIndex = CIRCULAR_TO_BASIC(index); + [_contents_array[basicIndex] release]; + circularFillHoleAt(self, basicIndex); + decrementCount(self); +} + +- (void) removeFirstObject +{ + if (!_count) + return; + [_contents_array[_start_index] release]; + _start_index = (_start_index + 1) % _capacity; + decrementCount(self); +} + +- (void) removeLastObject +{ + if (!_count) + return; + [_contents_array[CIRCULAR_TO_BASIC(_count-1)] release]; + decrementCount(self); +} + +- objectAtIndex: (unsigned)index +{ + CHECK_INDEX_RANGE_ERROR(index, _count); + return _contents_array[CIRCULAR_TO_BASIC(index)]; +} + +- (void) appendObject: newObject +{ + incrementCount(self); + [newObject retain]; + _contents_array[CIRCULAR_TO_BASIC(_count-1)] = newObject; +} + +- (void) prependElement: newObject +{ + incrementCount(self); + [newObject retain]; + _start_index = (_capacity + _start_index - 1) % _capacity; + _contents_array[_start_index] = newObject; +} + +- (void) insertElement: newObject atIndex: (unsigned)index +{ + unsigned basicIndex; + + CHECK_INDEX_RANGE_ERROR(index, _count+1); + incrementCount(self); + [newObject retain]; + basicIndex = CIRCULAR_TO_BASIC(index); + circularMakeHoleAt(self, basicIndex); + _contents_array[basicIndex] = newObject; +} + +- (void) replaceObjectAtIndex: (unsigned)index withObject: newObject +{ + unsigned basicIndex; + + CHECK_INDEX_RANGE_ERROR(index, _count); + [newObject retain]; + basicIndex = CIRCULAR_TO_BASIC(index); + [_contents_array[basicIndex] release]; + _contents_array[basicIndex] = newObject; +} + +- (void) swapAtIndeces: (unsigned)index1 : (unsigned)index2 +{ + id tmp; + + CHECK_INDEX_RANGE_ERROR(index1, _count); + CHECK_INDEX_RANGE_ERROR(index2, _count); + index1 = CIRCULAR_TO_BASIC(index1); + index2 = CIRCULAR_TO_BASIC(index2); + tmp = _contents_array[index1]; + _contents_array[index1] = _contents_array[index2]; + _contents_array[index2] = tmp; +} + +#if 0 +/* just temporary for debugging */ +- circularArrayPrintForDebugger +{ + int i; + + printf("_start_index=%d, _count=%d, _capacity=%d\n", + _start_index, _count, _capacity); + for (i = 0; i < _capacity; i++) + { + printf("%3d ", i); + } + printf("\n"); + for (i = 0; i < _capacity; i++) + { + printf("%3d ", _contents_array[i].int_t); + } + printf("\n"); + for (i = 0; i < _capacity; i++) + { + printf("%3d ", _contents_array[CIRCULAR_TO_BASIC(i)].int_t); + } + printf("\n"); + + return self; +} +#endif + +@end + diff --git a/Old/CircularArrayPrivate.h b/Old/CircularArrayPrivate.h new file mode 100644 index 000000000..4f47d5453 --- /dev/null +++ b/Old/CircularArrayPrivate.h @@ -0,0 +1,74 @@ +/* CircularArray definitions for the use of subclass implementations + Copyright (C) 1993,1994 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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 __CircularArrayPrivate_h_GNUSTEP_BASE_INCLUDE +#define __CircularArrayPrivate_h_GNUSTEP_BASE_INCLUDE + +#include + +#define CIRCULAR_TO_BASIC(INDEX) \ + ((INDEX + self->_start_index) % self->_capacity) + +#define BASIC_TO_CIRCULAR(INDEX) \ + ((INDEX + self->_capacity - self->_start_index) % self->_capacity) + +#define NEXT_CIRCULAR_INDEX(INDEX) \ + ((INDEX + 1) % self->_capacity) + +#define PREV_CIRCULAR_INDEX(INDEX) \ + ((INDEX + self->_capacity - 1) % self->_capacity) + +static inline void +circularMakeHoleAt(CircularArray *self, unsigned basicIndex) +{ + int i; + if (self->_start_index && basicIndex > self->_start_index) + { + for (i = self->_start_index; i < basicIndex; i++) + self->_contents_array[i-1] = self->_contents_array[i]; + } + else + { + for (i = CIRCULAR_TO_BASIC(self->_count-1); i >= basicIndex; i--) + self->_contents_array[i+1] = self->_contents_array[i]; + } + /* This is never called with _count == 0 */ +} + +static inline void +circularFillHoleAt(CircularArray *self, unsigned basicIndex) +{ + int i; + if (basicIndex > self->_start_index) + { + for (i = basicIndex; i > self->_start_index; i--) + self->_contents_array[i] = self->_contents_array[i-1]; + } + else + { + for (i = basicIndex; i < CIRCULAR_TO_BASIC(self->_count-1); i++) + self->_contents_array[i] = self->_contents_array[i+1]; + } +} + +#endif /* __CircularArrayPrivate_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/Coder.h b/Old/Coder.h new file mode 100644 index 000000000..ed40a71b6 --- /dev/null +++ b/Old/Coder.h @@ -0,0 +1,141 @@ +/* Interface for GNU Objective-C coder object for use serializing + Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: July 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 __Coder_h_GNUSTEP_BASE_INCLUDE +#define __Coder_h_GNUSTEP_BASE_INCLUDE + +#include +#include +#include +#include + +@class CStream; + + +/* The root abstract class for archiving */ + +@interface Coder : NSObject +{ + @public + int format_version; + CStream *cstream; + NSMapTable *classname_2_classname; /* for changing class names on r/w */ + int interconnect_stack_height; /* number of nested root objects */ +} + ++ setDebugging: (BOOL)f; + +@end + + +/* An abstract class for writing an archive */ + +@interface Encoder : Coder +{ + @public + /* xxx in_progress_table should actually be an NSHashTable, + but we are working around a bug right now. */ + NSMapTable *in_progress_table; /* objects begun writing, but !finished */ + NSMapTable *object_2_xref; /* objects already written */ + NSMapTable *object_2_fref; /* table of forward references */ + NSMapTable *const_ptr_2_xref; /* const pointers already written */ + unsigned fref_counter; /* Keep track of unused fref numbers */ +} + +- initForWritingToFile: (NSString*) filename; +- initForWritingToFile: (NSString*) filename + withCStreamClass: (Class) cStreamClass; +- initForWritingToFile: (NSString*) filename + withFormatVersion: (int) version + cStreamClass: (Class)scc + cStreamFormatVersion: (int) cStreamFormatVersion; + +- initForWritingToStream: (id ) s; +- initForWritingToStream: (id ) s + withCStreamClass: (Class) cStreamClass; +- initForWritingToStream: (id ) s + withFormatVersion: (int) version + cStreamClass: (Class) cStreamClass + cStreamFormatVersion: (int) cStreamFormatVersion; + ++ (BOOL) encodeRootObject: anObject + withName: (NSString*) name + toFile: (NSString*) filename; ++ (BOOL) encodeRootObject: anObject + withName: (NSString*) name + toStream: (id )stream; + +/* Defaults */ ++ (void) setDefaultStreamClass: sc; ++ defaultStreamClass; ++ (void) setDefaultCStreamClass: sc; ++ defaultCStreamClass; ++ (void) setDefaultFormatVersion: (int)fv; ++ (int) defaultFormatVersion; + +@end + +@interface Encoder (Encoding) +@end + + + +/* An abstract class for reading an archive. */ + +@interface Decoder : Coder +{ + NSZone *zone; /* zone in which to create objects */ + id xref_2_object; /* objects already read */ + id xref_2_object_root; /* objs read since last -startDecodoingI.. */ + NSMapTable *xref_2_const_ptr; /* const pointers already written */ + NSMapTable *fref_2_object; /* table of forward references */ + NSMapTable *address_2_fref; /* table of forward references */ +} + +/* These are class methods (and not instance methods) because the + header of the file or stream determines which subclass of Decoder + is created. */ + ++ newReadingFromFile: (NSString*) filename; ++ newReadingFromStream: (id )stream; + ++ decodeObjectWithName: (NSString* *) name + fromFile: (NSString*) filename; ++ decodeObjectWithName: (NSString* *) name + fromStream: (id )stream; + +@end + +@interface Decoder (Decoding) +@end + + +/* Extensions to NSObject for encoding and decoding. */ + +@interface NSObject (OptionalNewWithCoder) ++ newWithCoder: (Coder*)aDecoder; +@end + +GS_EXPORT id CoderSignatureMalformedException; + +#endif /* __Coder_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/Coder.m b/Old/Coder.m new file mode 100644 index 000000000..0cf281a6d --- /dev/null +++ b/Old/Coder.m @@ -0,0 +1,310 @@ +/* Implementation of GNU Objective-C coder object for use serializing + Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: July 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Exception strings */ +id CoderSignatureMalformedException = @"CoderSignatureMalformedException"; + +#define DEFAULT_FORMAT_VERSION 0 + +#define ROUND(V, A) \ + ({ typeof(V) __v=(V); typeof(A) __a=(A); \ + __a*((__v+__a-1)/__a); }) + +#define DOING_ROOT_OBJECT (interconnect_stack_height != 0) + +static BOOL debug_coder = NO; + + +@implementation Coder + ++ (void) initialize +{ + if (self == [Coder class]) + behavior_class_add_class (self, [NSCoderNonCore class]); +} + ++ setDebugging: (BOOL)f +{ + debug_coder = f; + return self; +} + + +/* Initialization. */ + +/* This is the designated initializer. But, don't call it yourself; + override it and call [super...] in subclasses. */ +- _initWithCStream: (id ) cs + formatVersion: (int) version +{ + format_version = version; + cstream = [cs retain]; + classname_2_classname = NULL; + interconnect_stack_height = 0; + return self; +} + +- init +{ + if ([self class] == [Coder class]) + { + [self shouldNotImplement:_cmd]; + return nil; + } + else + return [super init]; +} + +/* We must separate the idea of "closing" a coder and "deallocating" + a coder because of delays in deallocation due to -autorelease. */ +- (void) close +{ + [[cstream stream] close]; +} + +- (BOOL) isClosed +{ + return [[cstream stream] isClosed]; +} + +- (void) dealloc +{ + /* xxx No. [self _finishDecodeRootObject]; */ + [cstream release]; + [super dealloc]; +} + + +/* Access to instance variables. */ + +- cStream +{ + return cstream; +} + +- (int) formatVersion +{ + return format_version; +} + +- (void) resetCoder +{ + /* xxx Finish this */ + [self notImplemented:_cmd]; +} + +@end + + +/* To fool ourselves into thinking we can call all these + Encoding and Decoding methods. */ +@interface Coder (Coding) +@end + + + +@implementation Coder (NSCoderCompatibility) + + +/* The core methods */ + +- (void) encodeValueOfObjCType: (const char*)type + at: (const void*)address; +{ + [self encodeValueOfObjCType: type at: address withName: NULL]; +} + +- (void) decodeValueOfObjCType: (const char*)type + at: (void*)address +{ + [self decodeValueOfObjCType: type at: address withName: NULL]; +} + +- (void) encodeDataObject: (NSData*)data +{ + [self notImplemented:_cmd]; +} + +- (NSData*) decodeDataObject +{ + [self notImplemented:_cmd]; + return nil; +} + +- (unsigned int) versionForClassName: (NSString*)className +{ + [self notImplemented:_cmd]; + return 0; +} + +/* Override some methods in NSCoderNonCore */ + +- (void) encodeObject: (id)anObject +{ + [self encodeObject: anObject withName: NULL]; +} + +- (void) encodeBycopyObject: (id)anObject +{ + [self encodeBycopyObject: anObject withName: NULL]; +} + +- (void) encodeByrefObject: (id)anObject +{ + [self encodeByrefObject: anObject withName: NULL]; +} + +- (void) encodeConditionalObject: (id)anObject +{ + /* NeXT's implementation handles *forward* references by running + through the entire encoding process twice! GNU Coding can handle + forward references with only one pass. Therefore, however, GNU + Coding cannot return a *forward* reference from -decodeObject, so + here, assuming this call to -encodeConditionalObject: is mirrored + by a -decodeObject, we don't try to encode *forward* + references. + + Note that this means objects that use -encodeConditionalObject: + that are encoded in the GNU style might decode a nil where + NeXT-style encoded would not. I don't see this a huge problem; + at least not as bad as NeXT coding mechanism that actually causes + crashes in situations where GNU's does fine. Still, if we wanted + to fix this, we might be able to build a kludgy fix based on + detecting when this would happen, rewinding the stream to the + "conditional" point, and encoding again. Yuck. */ + + if ([self _coderReferenceForObject: anObject]) + [self encodeObject: anObject]; + else + [self encodeObject: nil]; +} + +- (void) encodeRootObject: (id)rootObject +{ + [self encodeRootObject: rootObject withName: NULL]; +} + +- (id) decodeObject +{ + /* This won't work for decoding GNU-style forward references because + once the GNU decoder finds the object later in the decoding, it + will back-patch by storing the id in &o... &o will point to some + weird location on the stack! This is why we make the GNU + implementation of -encodeConditionalObject: not encode forward + references. */ + id o; + [self decodeObjectAt: &o withName: NULL]; + return [o autorelease]; +} + +- (unsigned int) systemVersion +{ + return format_version; /* xxx Is this right? */ +} + +@end /* of (NSCoderCompatibility) */ + + +@implementation Coder (NSArchiverCompatibility) + + +/* Initializing an archiver */ + +- (id) initForWritingWithMutableData: (NSMutableData*)mdata +{ + [(id)self initForWritingToStream: [MemoryStream streamWithData: mdata]]; + return self; +} + +- (id) initForReadingWithData: (NSData*)data +{ + id ret = [[self class] newReadingFromStream: + [MemoryStream streamWithData:data]]; + [self release]; + return ret; +} + +/* Archiving Data */ + ++ (NSData*) archivedDataWithRootObject: (id)rootObject +{ + id d = [[NSMutableData alloc] init]; + id a = [[NSArchiver alloc] initForWritingWithMutableData:d]; + [a encodeRootObject:rootObject]; + return [d autorelease]; +} + ++ (BOOL) archiveRootObject: (id)rootObject toFile: (NSString*)path +{ + /* xxx fix this return value */ + id d = [self archivedDataWithRootObject:rootObject]; + [d writeToFile:path atomically:NO]; + return YES; +} + +/* Getting data from the archiver */ + ++ unarchiveObjectWithData: (NSData*) data +{ + return [self decodeObjectWithName: NULL + fromStream: [MemoryStream streamWithData:data]]; +} + ++ unarchiveObjectWithFile: (NSString*) path +{ + return [self decodeObjectWithName: NULL fromFile: path]; +} + +- (NSMutableData*) archiverData +{ + [self notImplemented:_cmd]; + return nil; +} + +@end diff --git a/Old/CoderPrivate.h b/Old/CoderPrivate.h new file mode 100644 index 000000000..30fba5e98 --- /dev/null +++ b/Old/CoderPrivate.h @@ -0,0 +1,66 @@ +/* Private interface for GNU Objective-C coder object for use serializing + Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: February 1996 + + 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 __CoderPrivate_h_GNUSTEP_BASE_INCLUDE +#define __CoderPrivate_h_GNUSTEP_BASE_INCLUDE + +#include +#include + +enum { + CODER_OBJECT_NIL = 0, + CODER_OBJECT, + CODER_OBJECT_ROOT, + CODER_OBJECT_REPEATED, + CODER_OBJECT_FORWARD_REFERENCE, + CODER_OBJECT_CLASS, + CODER_CLASS_NIL, + CODER_CLASS, + CODER_CLASS_REPEATED, + CODER_CONST_PTR_NULL, + CODER_CONST_PTR, + CODER_CONST_PTR_REPEATED +}; + +#define DOING_ROOT_OBJECT (interconnect_stack_height != 0) + +@interface Coder (Private) +- _initWithCStream: (id ) cs formatVersion: (int) version; +- (unsigned) _coderReferenceForObject: anObject; +@end + +#define SIGNATURE_FORMAT_STRING \ +@"GNU Objective C (%s %d.%d.%d) [%s %d]\n" + +#define WRITE_SIGNATURE_FORMAT_ARGS \ +STRINGIFY(GNUSTEP_BASE_PACKAGE_NAME), \ +GNUSTEP_BASE_MAJOR_VERSION, \ +GNUSTEP_BASE_MINOR_VERSION, \ +GNUSTEP_BASE_SUBMINOR_VERSION, \ +[self defaultDecoderClassname], \ +format_version + + +#define NO_SEL_TYPES "none" + +#endif /* __CoderPrivate_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/Coding.h b/Old/Coding.h new file mode 100644 index 000000000..2ea51fe0b --- /dev/null +++ b/Old/Coding.h @@ -0,0 +1,165 @@ +/* Protocol for GNU Objective-C objects that can write/read to a coder + Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: July 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 __Coding_h_GNUSTEP_BASE_INCLUDE +#define __Coding_h_GNUSTEP_BASE_INCLUDE + +#include + +/* #include + xxx Think about trying to get back in types, + but now there is a circular dependancy in the include files. */ + +@protocol CommonCoding +- (BOOL) isDecoding; +- (void) close; +- (BOOL) isClosed; ++ (int) defaultFormatVersion; +- cStream; +@end + +@protocol Encoding + +- (void) encodeValueOfObjCType: (const char*)type + at: (const void*)d + withName: (id /**/)name; + +- (void) encodeValueOfCType: (const char*)type + at: (const void*)d + withName: (id /**/)name; + +- (void) encodeWithName: (id /**/)name + valuesOfObjCTypes: (const char *)types, ...; + +- (void) encodeArrayOfObjCType: (const char *)type + count: (unsigned)c + at: (const void *)d + withName: (id /**/)name; + +- (void) encodeObject: anObj + withName: (id /**/)name; +- (void) encodeBycopyObject: anObj + withName: (id /**/)name; +- (void) encodeByrefObject: anObj + withName: (id /**/)name; + +- (void) encodeRootObject: anObj + withName: (id /**/)name; +- (void) encodeObjectReference: anObj + withName: (id /**/)name; +- (void) startEncodingInterconnectedObjects; +- (void) finishEncodingInterconnectedObjects; + +- (void) encodeAtomicString: (const char*)sp + withName: (id /**/)name; + +- (void) encodeClass: aClass; + +/* For inserting a name into a TextCoder stream */ +- (void) encodeName: (id /**/) n; + +/* For classes that want to keep track of recursion */ +- (void) encodeIndent; +- (void) encodeUnindent; + +- (void) encodeBytes: (const void *)b + count: (unsigned)c + withName: (id /**/)name; + +@end + +@protocol Decoding + +- (void) decodeValueOfObjCType: (const char*)type + at: (void*)d + withName: (id /**/ *) namePtr; + +- (void) decodeValueOfCType: (const char*)type + at: (void*)d + withName: (id /**/ *) namePtr; + +- (void) decodeWithName: (id /**/*)name + valuesOfObjCTypes: (const char *) types, ...; + +- (void) decodeArrayOfObjCType: (const char *)type + count: (unsigned)c + at: (void *)d + withName: (id /**/*)name; + +- (void) decodeObjectAt: (id*)anObjPtr + withName: (id /**/*)name; + +- (void) startDecodingInterconnectedObjects; +- (void) finishDecodingInterconnectedObjects; + +- (const char *) decodeAtomicStringWithName: (id /**/*) name; + +- decodeClass; + +/* For inserting a name into a TextCoder stream */ +- (void) decodeName: (id /**/ *)n; + +/* For classes that want to keep track of recursion */ +- (void) decodeIndent; +- (void) decodeUnindent; + +- (void) decodeBytes: (void *)b + count: (unsigned)c + withName: (id /**/ *) name; + +@end + +@interface NSObject (SelfCoding) + +- (void) encodeWithCoder: (id )anEncoder; +- (id) initWithCoder: (id )aDecoder; ++ (id) newWithCoder: (id )aDecoder; + +/* NOTE: + + If the class responds to +newWithCoder Coder will send it for + decoding, otherwise Coder will allocate the object itself and send + initWithCoder instead. + + +newWithCoder is useful because many classes keep track of their + instances and only allow one instance of each configuration. For + example, see the designated initializers of SocketPort, Connection, + and Proxy. + + Using +new.. instead of -init.. prevents us from having to waste + the effort of allocating space for an object to be decoded, then + immediately deallocating that space because we're just returning a + pre-existing object. + + The newWithCoder and initWithCoder methods must return the decoded + object. + + This is not a Protocol, because objects are not required to + implement newWithCoder or initWithCoder. They probably want to + implement one of them, though. + + -mccallum */ + +@end + +#endif /* __Coding_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/Collecting.h b/Old/Collecting.h new file mode 100644 index 000000000..7cbca2601 --- /dev/null +++ b/Old/Collecting.h @@ -0,0 +1,129 @@ +/* Protocol for Objective-C objects that hold collections of elements. + Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: May 1993 + + 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. +*/ + +/* The protocol is root of the collection protocol heirarchy. + + The protocol defines the most general interface to a + collection of elements. Elements can be added, removed, and replaced. + The contents can be tested, enumerated, and enumerated through various + filters. Elements may be objects, or any C type included in the + "elt" union given in elt.h, but all elements of a collection must be of + the same C type. +*/ + +#ifndef __Collecting_h_GNUSTEP_BASE_INCLUDE +#define __Collecting_h_GNUSTEP_BASE_INCLUDE + +#include +#include +#include + +@protocol ConstantCollecting + +// INITIALIZING; +- init; +- initWithObjects: (id*)objc count: (unsigned)c; +- initWithObjects: firstObject, ...; +- initWithObjects: firstObject rest: (va_list)ap; +- initWithContentsOf: (id )aCollection; + +// QUERYING COUNTS; +- (BOOL) isEmpty; +- (unsigned) count; +- (BOOL) containsObject: anObject; +- (unsigned) occurrencesOfObject: anObject; + +// COMPARISON WITH OTHER COLLECTIONS; +- (BOOL) isSubsetOf: (id )aCollection; +- (BOOL) isDisjointFrom: (id )aCollection; +- (BOOL) isEqual: anObject; +- (int) compare: anObject; +- (BOOL) contentsEqual: (id )aCollection; + +// PROPERTIES OF CONTENTS; +- (BOOL) trueForAllObjectsByInvoking: (id )anInvocation; +- (BOOL) trueForAnyObjectsByInvoking: (id )anInvocation; +- detectObjectByInvoking: (id )anInvocation; +- maxObject; +- minObject; + +// ENUMERATING +- (id ) objectEnumerator; +- (void) withObjectsInvoke: (id )anInvocation; +- (void) withObjectsInvoke: (id )anInvocation whileTrue:(BOOL *)flag; +- (void) makeObjectsPerform: (SEL)aSel; +- (void) makeObjectsPerform: (SEL)aSel withObject: argObject; + +// FILTERED ENUMERATING; +- (void) withObjectsTrueByInvoking: (id )testInvocation + invoke: (id )anInvocation; +- (void) withObjectsFalseByInvoking: (id )testInvocation + invoke: (id )anInvocation; +- (void) withObjectsTransformedByInvoking: (id )transInvocation + invoke: (id )anInvocation; + +// LOW-LEVEL ENUMERATING; +- (void*) newEnumState; +- nextObjectWithEnumState: (void**)enumState; +- (void) freeEnumState: (void**)enumState; + +// COPYING; +- allocCopy; +- emptyCopy; +- emptyCopyAs: (Class)aCollectionClass; +- shallowCopy; +- shallowCopyAs: (Class)aCollectionClass; +- copyAs: (Class)aCollectionClass; +- species; + +@end + + +@protocol Collecting + +// ADDING; +- (void) addObject: newObject; +- (void) addObjectIfAbsent: newObject; +- (void) addContentsOf: (id )aCollection; +- (void) addContentsIfAbsentOf: (id )aCollection; +- (void) addWithObjects: (id*)objc count: (unsigned)c; +- (void) addObjects: firstObject, ...; +- (void) addObjects: firstObject rest: (va_list)ap; + +// REMOVING; +- (void) removeObject: oldObject; +- (void) removeAllOccurrencesOfObject: oldObject; +- (void) removeContentsIn: (id )aCollection; +- (void) removeContentsNotIn: (id )aCollection; +- (void) uniqueContents; +- (void) empty; + +// REPLACING; +- (void) replaceObject: oldObject withObject: newObject; +- (void) replaceAllOccurrencesOfObject: oldObject withObject: newObject; + +@end + +#define NO_OBJECT nil + +#endif /* __Collecting_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/Collection.h b/Old/Collection.h new file mode 100644 index 000000000..6586ebaad --- /dev/null +++ b/Old/Collection.h @@ -0,0 +1,102 @@ +/* Interface for Objective-C Collection object + Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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. +*/ + +/* This is the abstract superclass that satisfies the Collecting + protocol, without using any instance variables. +*/ + +#ifndef __Collection_h_GNUSTEP_BASE_INCLUDE +#define __Collection_h_GNUSTEP_BASE_INCLUDE + +#include +#include +#include +#include + +@interface ConstantCollection : NSObject +- printForDebugger; /* This method will disappear later. */ +@end + +@interface Collection : ConstantCollection +@end + +@interface Enumerator : NSObject +{ + id collection; + void *enum_state; +} +@end + +#define FOR_COLLECTION(ACOLL, ELT) \ +{ \ + void *_es = [ACOLL newEnumState]; \ + while ((ELT = [ACOLL nextObjectWithEnumState: &_es])) \ + { + +#define END_FOR_COLLECTION(ACOLL) \ + } \ + [ACOLL freeEnumState: &_es]; \ +} + +#define FOR_COLLECTION_WHILE_TRUE(ACOLL, ELT, FLAG) \ +{ \ + void *_es = [ACOLL newEnumState]; \ + while (FLAG && (ELT = [ACOLL nextObjectWithEnumState: &_es])) \ + { + +#define END_FOR_COLLECTION_WHILE_TRUE(ACOLL) \ + } \ + [ACOLL freeEnumState: &_es]; \ +} + +/* The only subclassResponsibilities in Collection are: + + addElement: + removeElement: + getNextElement:withEnumState: + empty + + But subclasses may need to override the following for correctness: + + contentType + comparisonFunction + + but subclasses will want to override others as well in order to + increase efficiency, especially: + + count + + and perhaps: + + includesElement: + occurrencesOfElement: + uniqueContents + withElementsCall:whileTrue: + withElementsCall: + isEmpty + releaseObjects + +*/ + +#endif /* __Collection_h_GNUSTEP_BASE_INCLUDE */ + diff --git a/Old/Collection.m b/Old/Collection.m new file mode 100644 index 000000000..609c23953 --- /dev/null +++ b/Old/Collection.m @@ -0,0 +1,839 @@ +/* Implementation for Objective-C Collection object + Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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. +*/ + +#include +#include +#include +#include +#include /* for -contentsEqual: */ +#include /* for -safeWithElementsCall: */ +#include +#include + +@implementation Enumerator + +- initWithCollection: coll +{ + self = [super init]; + if (self) + { + collection = [coll retain]; + enum_state = [coll newEnumState]; + } + return self; +} + +- nextObject +{ + return [collection nextObjectWithEnumState: &enum_state]; +} + +- (void) dealloc +{ + [collection freeEnumState: &enum_state]; + [collection release]; + [super dealloc]; +} + +@end + +@implementation ConstantCollection + + +// INITIALIZING AND RELEASING; + +- init +{ + return [self initWithObjects: NULL count: 0]; +} + +// This is the designated initializer of this class; +- initWithObjects: (id*)objc count: (unsigned)c +{ + [self subclassResponsibility: _cmd]; + return self; +} + +- initWithObjects: firstObject, ... +{ + va_list ap; + va_start(ap, firstObject); + self = [self initWithObjects:firstObject rest:ap]; + va_end(ap); + return self; +} + +#define INITIAL_OBJECTS_SIZE 10 +- initWithObjects: firstObject rest: (va_list)ap +{ + id *objects; + int i = 0; + int s = INITIAL_OBJECTS_SIZE; + + OBJC_MALLOC(objects, id, s); + if (firstObject != nil) + { + objects[i++] = firstObject; + while ((objects[i++] = va_arg(ap, id))) + { + if (i >= s) + { + s *= 2; + OBJC_REALLOC(objects, id, s); + } + } + } + self = [self initWithObjects:objects count:i-1]; + OBJC_FREE(objects); + return self; +} + +/* Subclasses can override this for efficiency. For example, Array can + init itself with enough capacity to hold aCollection. */ +- initWithContentsOf: (id )aCollection +{ + int count = [aCollection count]; + id contents_array[count]; + id o; + int i = 0; + + FOR_COLLECTION(aCollection, o) + { + contents_array[i++] = o; + } + END_FOR_COLLECTION(aCollection); + return [self initWithObjects: contents_array count: count]; +} + +- (void) dealloc +{ + /* xxx Get rid of this since Set, Bag, Dictionary, and String + subclasses don't want to use it? */ + [self _collectionReleaseContents]; + [self _collectionDealloc]; + [super dealloc]; +} + + +// QUERYING COUNTS; + +- (BOOL) isEmpty +{ + return ([self count] == 0); +} + +// Inefficient, so should be overridden in subclasses; +- (unsigned) count +{ + unsigned n = 0; + id o; + + FOR_COLLECTION(self, o) + { + n++; + } + END_FOR_COLLECTION(self); + return n; +} + +// Potentially inefficient, may be overridden in subclasses; +- (BOOL) containsObject: anObject +{ + id o; + FOR_COLLECTION (self, o) + { + if ([anObject isEqual: o]) + return YES; + } + END_FOR_COLLECTION(self); + return NO; +} + +- (unsigned) occurrencesOfObject: anObject +{ + unsigned count = 0; + id o; + + FOR_COLLECTION(self, o) + { + if ([anObject isEqual: o]) + count++; + } + END_FOR_COLLECTION(self); + return count; +} + + +// COMPARISON WITH OTHER COLLECTIONS; + +- (BOOL) isSubsetOf: (id )aCollection +{ + id o; + FOR_COLLECTION (self, o) + { + if (![aCollection containsObject: o]) + return NO; + } + END_FOR_COLLECTION (self); + return YES; +} + +- (BOOL) isDisjointFrom: (id )aCollection +{ + // Use objc_msg_lookup here also; + BOOL flag = YES; + id o; + + FOR_COLLECTION_WHILE_TRUE(self, o, flag) + { + if (![aCollection containsObject: o]) + flag = NO; + } + END_FOR_COLLECTION_WHILE_TRUE(self); + return !flag; +} + +// xxx How do we want to compare unordered contents?? ; +- (int) compareContentsOf: (id )aCollection +{ + if ([self contentsEqual:aCollection]) + return 0; + if (self > aCollection) + return 1; + return -1; +} + +- (BOOL) isEqual: anObject +{ + if (self == anObject) + return YES; + if ( [self contentsEqual: anObject] ) + return YES; + else + return NO; +} + +// Deal with this in IndexedCollection also ; +// How do we want to compare collections? ; +- (int) compare: anObject +{ + if ([self isEqual:anObject]) + return 0; + if (self > anObject) + return 1; + return -1; +} + +- (BOOL) contentsEqual: (id )aCollection +{ + id bag, o; + BOOL flag; + + if ([self count] != [aCollection count]) + return NO; + bag = [[Bag alloc] initWithContentsOf:aCollection]; + flag = YES; + FOR_COLLECTION_WHILE_TRUE (self, o, flag) + { + if ([bag containsObject: o]) + [bag removeObject: o]; + else + flag = NO; + } + END_FOR_COLLECTION_WHILE_TRUE(self); + if ((!flag) || [bag count]) + flag = NO; + else + flag = YES; + [bag release]; + return flag; +} + + +// PROPERTIES OF CONTENTS; + +- (BOOL) trueForAllObjectsByInvoking: (id )anInvocation +{ + BOOL flag = YES; + id o; + + FOR_COLLECTION_WHILE_TRUE(self, o, flag) + { + [anInvocation invokeWithObject: o]; + if (![anInvocation returnValueIsTrue]) + flag = NO; + } + END_FOR_COLLECTION_WHILE_TRUE(self); + return flag; +} + +- (BOOL) trueForAnyObjectsByInvoking: (id )anInvocation; +{ + BOOL flag = YES; + id o; + + FOR_COLLECTION_WHILE_TRUE(self, o, flag) + { + [anInvocation invokeWithObject: o]; + if ([anInvocation returnValueIsTrue]) + flag = NO; + } + END_FOR_COLLECTION_WHILE_TRUE(self); + return !flag; +} + +- detectObjectByInvoking: (id )anInvocation; +{ + BOOL flag = YES; + id detectedObject = nil; + id o; + + FOR_COLLECTION_WHILE_TRUE(self, o, flag) + { + [anInvocation invokeWithObject: o]; + if ([anInvocation returnValueIsTrue]) + { + flag = NO; + detectedObject = o; + } + } + END_FOR_COLLECTION_WHILE_TRUE(self); + if (flag) + return NO_OBJECT; + else + return detectedObject; +} + +- maxObject +{ + id o, max = nil; + BOOL firstTime = YES; + + FOR_COLLECTION(self, o) + { + if (firstTime) + { + firstTime = NO; + max = o; + } + else + { + if ([o compare: max] > 0) + max = o; + } + } + END_FOR_COLLECTION(self); + return max; +} + +- minObject +{ + id o, min = nil; + BOOL firstTime = YES; + + FOR_COLLECTION(self, o) + { + if (firstTime) + { + firstTime = NO; + min = o; + } + else + { + if ([o compare: min] < 0) + min = o; + } + } + END_FOR_COLLECTION(self); + return min; +} + +/* Consider adding: + - maxObjectByInvoking: (id )anInvocation; + - minObjectByInvoking: (id )anInvocation; + */ + + +// ENUMERATING; + +- (id ) objectEnumerator +{ + return [[[Enumerator alloc] initWithCollection: self] + autorelease]; +} + +- (void) withObjectsInvoke: (id )anInvocation +{ + id o; + + FOR_COLLECTION(self, o) + { + [anInvocation invokeWithObject: o]; + } + END_FOR_COLLECTION(self); +} + +- (void) withObjectsInvoke: (id )anInvocation whileTrue:(BOOL *)flag; +{ + id o; + + FOR_COLLECTION_WHILE_TRUE(self, o, *flag) + { + [anInvocation invokeWithObject: o]; + } + END_FOR_COLLECTION_WHILE_TRUE(self); +} + +- (void) makeObjectsPerform: (SEL)aSel +{ + id o; + + FOR_COLLECTION(self, o) + { + [o performSelector: aSel]; + } + END_FOR_COLLECTION(self); +} + +- (void) makeObjectsPerform: (SEL)aSel withObject: argObject +{ + id o; + + FOR_COLLECTION(self, o) + { + [o performSelector: aSel withObject: argObject]; + } + END_FOR_COLLECTION(self); +} + + + +// FILTERED ENUMERATING; + +- (void) withObjectsTrueByInvoking: (id )testInvocation + invoke: (id )anInvocation +{ + id o; + + FOR_COLLECTION(self, o) + { + [testInvocation invokeWithObject: o]; + if ([testInvocation returnValueIsTrue]) + [anInvocation invokeWithObject: o]; + } + END_FOR_COLLECTION(self); +} + +- (void) withObjectsFalseByInvoking: (id )testInvocation + invoke: (id )anInvocation +{ + id o; + + FOR_COLLECTION(self, o) + { + [testInvocation invokeWithObject: o]; + if (![testInvocation returnValueIsTrue]) + [anInvocation invokeWithObject: o]; + } + END_FOR_COLLECTION(self); +} + +- (void) withObjectsTransformedByInvoking: (id )transInvocation + invoke: (id )anInvocation +{ + id o; + + FOR_COLLECTION(self, o) + { + [transInvocation invokeWithObject: o]; + [anInvocation invokeWithObject: [transInvocation objectReturnValue]]; + } + END_FOR_COLLECTION(self); +} + + + +// LOW-LEVEL ENUMERATING; + +- (void*) newEnumState +{ + return (void*)0; +} + +- nextObjectWithEnumState: (void**)enumState; +{ + [self subclassResponsibility: _cmd]; + return NO; +} + +- (void) freeEnumState: (void**)enumState +{ + *enumState = (void*)0; +} + + + +// COPYING; + +- allocCopy +{ + return NSCopyObject (self, 0, [self zone]); +} + +// the copy to be filled by -shallowCopyAs: etc... ; +- emptyCopy +{ + // This will copy all instance vars; + // Subclasses will have to change instance vars like Array's _contents_array; + return [self allocCopy]; +} + +// the copy to be filled by -shallowCopyAs: etc... ; +- emptyCopyAs: (Class)aCollectionClass +{ + if (aCollectionClass == [self species]) + return [self emptyCopy]; + else + return [[(id)aCollectionClass alloc] init]; +} + +- shallowCopy +{ + return [self shallowCopyAs:[self species]]; +} + +- shallowCopyAs: (Class)aCollectionClass +{ + id newColl = [self emptyCopyAs:aCollectionClass]; + //#warning fix this addContentsOf for ConstantCollection + [newColl addContentsOf:self]; + return newColl; +} + +/* We can avoid the ugly [self safeWithElementsCall:doIt]; + in -deepen with something like this instead. + This fits with a scheme in which we get rid of the -deepen method, an + idea that I like since calling deepen on an object that has not just + been -shallowCopy'ed can cause major memory leakage. */ +- copyAs: (id )aCollectionClass +{ + id newColl = [self emptyCopyAs: (Class)aCollectionClass]; + id o; + + FOR_COLLECTION(self, o) + { + //#warning fix this addObject for ConstantCollection + id n = [o copy]; + [newColl addObject:n]; + [n release]; + } + END_FOR_COLLECTION(self); + return newColl; +} + +- species +{ + return [self class]; +} + + +// EXTRAS; + +- (const char *) libobjectsLicense +{ + const char *licenseString = + "Copyright (C) 1993,1994,1995,1996 Free Software Foundation, Inc.\n" + "\n" + "Chief Maintainer: Andrew McCallum \n" + "\n" + "This object is part of the GNUstep Base Library.\n" + "\n" + "This library is free software; you can redistribute it and/or\n" + "modify it under the terms of the GNU Library General Public\n" + "License as published by the Free Software Foundation; either\n" + "version 2 of the License, or (at your option) any later version.\n" + "\n" + "This library is distributed in the hope that it will be useful,\n" + "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" + "Library General Public License for more details.\n" + "\n" + "You should have received a copy of the GNU Library General Public\n" + "License along with this library; if not, write to the Free\n" + "Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.\n"; + return licenseString; +} + +- printForDebugger +{ + id o; + FOR_COLLECTION(self, o) + { + printf("%s ", [[o description] cString]); + } + END_FOR_COLLECTION(self); + printf(": %s\n", object_get_class_name (self)); + return self; +} + +- (void) encodeWithCoder: aCoder +{ + [self _encodeCollectionWithCoder:aCoder]; + [self _encodeContentsWithCoder:aCoder]; +} + +- initWithCoder: aCoder +{ + [self _initCollectionWithCoder:aCoder]; + [self _decodeContentsWithCoder:aCoder]; + return self; +} + +@end + + +@implementation ConstantCollection (ArchivingHelpers) + +- (void) _encodeCollectionWithCoder: aCoder +{ + [super encodeWithCoder:aCoder]; + // there are no instance vars; + return; +} + +- _initCollectionWithCoder: aCoder +{ + // there are no instance vars; + return [super initWithCoder:aCoder]; +} + +- (void) _encodeContentsWithCoder: (id )aCoder +{ + unsigned int count = [self count]; + id o; + + [aCoder encodeValueOfCType: @encode(unsigned) + at: &count + withName: @"Collection content count"]; + FOR_COLLECTION(self, o) + { + [aCoder encodeObject: o + withName:@"Collection element"]; + } + END_FOR_COLLECTION(self); +} + +- (void) _decodeContentsWithCoder: (id )aCoder +{ + id *content_array; + unsigned int count, i; + + [aCoder decodeValueOfCType:@encode(unsigned) + at:&count + withName:NULL]; + content_array = alloca (sizeof (id) * count); + for (i = 0; i < count; i++) + [aCoder decodeObjectAt: &(content_array[i]) + withName:NULL]; + [self initWithObjects: content_array count: count]; + for (i = 0; i < count; i++) + [content_array[i] release]; +} + +@end + + +@implementation ConstantCollection (DeallocationHelpers) + +/* This must work without sending any messages to content objects. + Content objects already may be dealloc'd when this is executed. */ +- (void) _collectionEmpty +{ + [self subclassResponsibility:_cmd]; +} + +- (void) _collectionReleaseContents +{ + int c = [self count]; + if (c) + { + id *array = (id*) alloca (c * sizeof(id)); + int i = 0; + void *es = [self newEnumState]; + id o; + while ((o = [self nextObjectWithEnumState:&es])) + { + array[i++] = o; + } + [self freeEnumState: &es]; + for (i = 0; i < c; i++) + [array[i] release]; + } +} + +- (void) _collectionDealloc +{ + return; +} + +@end + + +@implementation Collection + +// ADDING; + +- (void) addObject: anObject +{ + [self subclassResponsibility:_cmd]; +} + +- (void) addObjectIfAbsent: newObject; +{ + if (![self containsObject: newObject]) + [self addObject: newObject]; +} + +- (void) addContentsOf: (id )aCollection +{ + id o; + + FOR_COLLECTION(aCollection, o) + { + [self addObject: o]; + } + END_FOR_COLLECTION(aCollection); +} + +- (void) addContentsIfAbsentOf: (id )aCollection +{ + id o; + + FOR_COLLECTION(aCollection, o) + { + if (![self containsObject:o]) + [self addObject: o]; + } + END_FOR_COLLECTION(aCollection); +} + +- (void) addWithObjects: (id*)objc count: (unsigned)c +{ + [self notImplemented: _cmd]; +} + +- (void) addObjects: firstObject, ... +{ + [self notImplemented: _cmd]; +} + +- (void) addObjects: firstObject rest: (va_list)ap +{ + [self notImplemented: _cmd]; +} + + +// REMOVING AND REPLACING; + +- (void) removeObject: oldObject +{ + [self subclassResponsibility: _cmd]; +} + +- (void) removeAllOccurrencesOfObject: oldObject +{ + while ([self containsObject: oldObject]) + [self removeObject: oldObject]; +} + +- (void) removeContentsIn: (id )aCollection +{ + id o; + + FOR_COLLECTION(aCollection, o) + { + [self removeObject: o]; + } + END_FOR_COLLECTION(aCollection); +} + +- (void) removeContentsNotIn: (id )aCollection +{ + id o; + + FOR_COLLECTION(self, o) + { + if (![aCollection containsObject: o]) + [self removeObject: o]; + } + END_FOR_COLLECTION(self); +} + +- (void) uniqueContents +{ + id cp = [self shallowCopy]; + int count; + id o; + + FOR_COLLECTION(cp, o) + { + count = [self occurrencesOfObject: o]; + if (!count) + continue; + while (count--) + [self removeObject: o]; + } + END_FOR_COLLECTION(cp); +} + +/* May be inefficient. Could be overridden; */ +- (void) empty +{ + if ([self isEmpty]) + return; + [self _collectionReleaseContents]; + [self _collectionEmpty]; +} + + +// REPLACING; + +- (void) replaceObject: oldObject withObject: newObject +{ + if ([newObject isEqual: newObject]) + return; + [oldObject retain]; + [self removeObject: oldObject]; + [self addObject: newObject]; + [oldObject release]; +} + +- (void) replaceAllOccurrencesOfObject: oldObject withObject: newObject +{ + if ([oldObject isEqual: newObject]) + return; + while ([self containsObject: oldObject]) + [self replaceObject: oldObject withObject: newObject]; +} + +@end diff --git a/Old/CollectionPrivate.h b/Old/CollectionPrivate.h new file mode 100644 index 000000000..07f4f5b31 --- /dev/null +++ b/Old/CollectionPrivate.h @@ -0,0 +1,50 @@ +/* Collection definitions for the use of subclass implementations only + Copyright (C) 1993,1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: May 1993 + + 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 __CollectionPrivate_h_GNUSTEP_BASE_INCLUDE +#define __CollectionPrivate_h_GNUSTEP_BASE_INCLUDE + +@interface ConstantCollection (ArchivingHelpers) +/* These methods should never be called except in order, and inside + -encodeWithCoder: and -decodeWithCoder: */ +- (void) _encodeCollectionWithCoder: (id )aCoder; +- _initCollectionWithCoder: (id )aCoder; +- (void) _encodeContentsWithCoder: (id )aCoder; +- (void) _decodeContentsWithCoder: (id )aCoder; +@end + +@interface ConstantCollection (DeallocationHelpers) + +/* Empty the internals of a collection after the contents have + already been released. */ +- (void) _collectionEmpty; + +- (void) _collectionReleaseContents; + +/* Deallocate the internals of a collection after the contents + have already been released. */ +- (void) _collectionDealloc; + +@end + +#endif /* __CollectionPrivate_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/Decoder.m b/Old/Decoder.m new file mode 100644 index 000000000..3799cec58 --- /dev/null +++ b/Old/Decoder.m @@ -0,0 +1,878 @@ +/* Abstract class for reading objects from a stream + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: February 1996, with core from Coder, created 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern BOOL sel_types_match(const char* t1, const char* t2); + +static int debug_coder = 0; + +@implementation Decoder + +static id dummyObject; + ++ (void)initialize +{ + BOOL beenHere = NO; + + if (beenHere == NO) + { + beenHere = YES; + dummyObject = [NSObject new]; + } +} + + +/* Signature Handling. */ + ++ (void) readSignatureFromCStream: (id ) cs + getClassname: (char *) name + formatVersion: (int*) version +{ + int got; + char package_name[64]; + int major_version; + int minor_version; + int subminor_version; + + /* SIGNATURE_FORMAT_STRING is defined in gnustep/base/CoderPrivate.h */ + got = [[cs stream] readFormat: SIGNATURE_FORMAT_STRING, + &package_name, + &major_version, + &minor_version, + &subminor_version, + name, version]; + if (got != 6) + [NSException raise: CoderSignatureMalformedException + format: @"Decoder found a malformed signature"]; +} + +/* This is the designated initializer. */ ++ newReadingFromStream: (id ) stream +{ + id cs = [CStream cStreamReadingFromStream: stream]; + char name[128]; /* Max classname length. */ + int version; + Decoder *new_coder; + + [self readSignatureFromCStream: cs + getClassname: name + formatVersion: &version]; + + new_coder = [[objc_lookup_class(name) alloc] + _initWithCStream: cs + formatVersion: version]; + new_coder->xref_2_object = NULL; + new_coder->xref_2_object_root = NULL; + new_coder->fref_2_object = NULL; + new_coder->address_2_fref = NULL; + new_coder->zone = NSDefaultMallocZone(); + return new_coder; +} + ++ newReadingFromFile: (NSString*) filename +{ + return [self newReadingFromStream: + [StdioStream streamWithFilename: filename + fmode: "r"]]; +} + ++ decodeObjectWithName: (NSString* *) name + fromStream: (id )stream; +{ + id c, o; + c = [self newReadingFromStream:stream]; + [c decodeObjectAt: &o withName: name]; + [c release]; + return [o autorelease]; +} + ++ decodeObjectWithName: (NSString* *) name + fromFile: (NSString*) filename; +{ + return [self decodeObjectWithName: name + fromStream: + [StdioStream streamWithFilename:filename fmode: "r"]]; +} + + + +/* Functions and methods for keeping cross-references + so objects that were already read can be referred to again. */ + +/* These _coder... methods may be overriden by subclasses so that + cross-references can be kept differently. */ + +- (unsigned) _coderCreateReferenceForObject: anObj +{ + if (!xref_2_object) + { + xref_2_object = [NSMutableArray new]; + /* Append an object so our xref numbers are in sync with the + Encoders, which start at 1. */ + [xref_2_object addObject: dummyObject]; + } + if (debug_coder) + fprintf (stderr, "Decoder registering object xref %u\n", + [xref_2_object count] - 1); + [xref_2_object addObject: anObj]; // xxx but this will retain anObj. NO. + /* This return value should be the same as the index of anObj + in xref_2_object. */ + return ([xref_2_object count] - 1); +} + +- (void) _coderSubstituteObject: anObj atReference: (unsigned)xref +{ + [xref_2_object replaceObjectAtIndex: xref withObject: anObj]; +} + +- _coderObjectAtReference: (unsigned)xref +{ + NSParameterAssert (xref_2_object); + return [xref_2_object objectAtIndex: xref]; +} + + +/* The methods for the root object table. The *root* object table + (XREF_2_OBJECT_ROOT) isn't really used for much right now, but it + may be in the future. For now, most of the work is don't by + XREF_2_OBJECT. */ + +- (void) _coderPushRootObjectTable +{ + if (!xref_2_object_root) + xref_2_object_root = [NSMutableArray new]; +} + +- (void) _coderPopRootObjectTable +{ + NSParameterAssert (xref_2_object_root); + if (!interconnect_stack_height) + { + [xref_2_object_root release]; + xref_2_object_root = NULL; + } +} + +- (unsigned) _coderCreateReferenceForInterconnectedObject: anObj +{ + if (!xref_2_object_root) + { + xref_2_object_root = [NSMutableArray new]; + /* Append an object so our xref numbers are in sync with the + Encoders, which start at 1. */ + [xref_2_object_root addObject: dummyObject]; + } + [xref_2_object_root addObject: anObj]; + /* This return value should be the same as the index of anObj + in xref_2_object_root. */ + return ([xref_2_object_root count] - 1); +} + +- _coderTopRootObjectTable +{ + NSParameterAssert (xref_2_object_root); + return xref_2_object_root; +} + + +/* Using the next three methods, subclasses can change the way that + const pointers (like SEL, Class, Atomic strings, etc) are + archived. */ + +- (unsigned) _coderCreateReferenceForConstPtr: (const void*)ptr +{ + unsigned xref; + + if (!xref_2_const_ptr) + { + xref_2_const_ptr = NSCreateMapTable (NSIntMapKeyCallBacks, + NSNonOwnedPointerMapValueCallBacks, + 0); + /* Append an object so our xref numbers are in sync with the + Encoders, which start at 1. */ + NSMapInsert (xref_2_const_ptr, (void*)0, (void*)1); + } + xref = NSCountMapTable (xref_2_const_ptr); + NSMapInsert (xref_2_const_ptr, (void*)xref, ptr); + return xref; +} + +- (const void*) _coderConstPtrAtReference: (unsigned)xref; +{ + NSParameterAssert (xref_2_const_ptr); + return NSMapGet (xref_2_const_ptr, (void*)xref); +} + + +/* Here are the methods for forward object references. */ + +- (void) _coderPushForwardObjectTable +{ +#if 0 + if (!fref_stack) + fref_stack = o_list_of_void_p (); + o_list_append_element (fref_stack, NSCreateMap (...)); +#endif + if (!address_2_fref) + address_2_fref = NSCreateMapTable (NSNonOwnedPointerMapKeyCallBacks, + NSIntMapValueCallBacks, 0); + +} + +- (void) _coderPopForwardObjectTable +{ + NSParameterAssert (address_2_fref); + if (!interconnect_stack_height) + { + NSFreeMapTable (address_2_fref); + address_2_fref = NULL; + } +} + +- (void) _coderSatisfyForwardReference: (unsigned)fref withObject: anObj +{ + NSParameterAssert (address_2_fref); + if (!fref_2_object) + /* xxx Or should this be NSObjectMapValueCallBacks, so we make + sure the object doesn't get released before we can resolve + references with it? */ + fref_2_object = NSCreateMapTable (NSIntMapKeyCallBacks, + NSNonOwnedPointerMapValueCallBacks, 0); + /* There should only be one object for each fref. */ + NSAssert (!NSMapGet (fref_2_object, (void*)fref), + @"Should have only been one object for each fref"); + NSMapInsert (fref_2_object, (void*)fref, anObj); +} + +- (void) _coderAssociateForwardReference: (unsigned)fref + withObjectAddress: (void*)addr +{ + /* Register ADDR as associated with FREF; later we will put id + associated with FREF at ADDR. */ + NSParameterAssert (address_2_fref); + /* There should not be duplicate addresses */ + NSAssert (!NSMapGet (address_2_fref, addr), @"Duplicate addresses"); + NSMapInsert (address_2_fref, addr, (void*)fref); +} + +- (void) _coderResolveTopForwardReferences +{ + /* Enumerate the forward references and put them at the proper addresses. */ + NSMapEnumerator me; + void *fref; + void *addr; + + if (!address_2_fref) + return; + + /* Go through all the addresses that are needing to be filled + in with forward references, and put the correct object there. + If fref_2_object does not contain an object for fref, (i.e. there + was no satisfier for the forward reference), put nil there. */ + me = NSEnumerateMapTable (address_2_fref); + while (NSNextMapEnumeratorPair (&me, &addr, &fref)) + *(id*)addr = (id) NSMapGet (fref_2_object, fref); +} + + +/* This is the Coder's interface to the over-ridable + "_coderCreateReferenceForObject" method. Do not override it. It + handles the xref_2_object_root. */ + +- (unsigned) _coderInternalCreateReferenceForObject: anObj +{ + unsigned xref = [self _coderCreateReferenceForObject: anObj]; + if (DOING_ROOT_OBJECT) + [self _coderCreateReferenceForInterconnectedObject: anObj]; + return xref; +} + +- (void) _coderInternalSubstituteObject: anObj atReference: (unsigned)xref +{ + [self _coderSubstituteObject: anObj atReference: xref]; + /* xxx If we ever use the root object table, do something with it also. */ +} + + + +/* Method for decoding things. */ + +- (void) decodeValueOfCType: (const char*)type + at: (void*)d + withName: (NSString* *)namePtr +{ + [cstream decodeValueOfCType:type + at:d + withName:namePtr]; +} + +- (void) decodeBytes: (void *)b + count: (unsigned)c + withName: (NSString* *) name +{ + int actual_count; + /* xxx Is this what we want? + It won't be cleanly readable in TextCStream's. */ + [cstream decodeName: name]; + actual_count = [[cstream stream] readBytes: b length: c]; + NSAssert2 (actual_count == c, + @"expected to read %d bytes, read %d bytes",c,actual_count); +} + +- (unsigned char) decodeTag +{ + if ([cstream respondsToSelector: @selector(decodeTag)]) + return [(id)cstream decodeTag]; + { + unsigned char t; + [self decodeValueOfCType:@encode(unsigned char) + at:&t + withName:NULL]; + return t; + } +} + +- decodeClass +{ + unsigned char tag; + char *class_name; + int class_version; + id ret = Nil; + + [self decodeIndent]; + tag = [self decodeTag]; + switch (tag) + { + case CODER_CLASS_NIL: + break; + case CODER_CLASS_REPEATED: + { + unsigned xref; + [self decodeValueOfCType: @encode(unsigned) + at: &xref + withName: NULL]; + ret = (id) [self _coderConstPtrAtReference: xref]; + if (!ret) + [NSException + raise: NSGenericException + format: @"repeated class cross-reference number %u not found", + xref]; + break; + } + case CODER_CLASS: + { + [self decodeValueOfCType: @encode(char*) + at: &class_name + withName: NULL]; + [self decodeValueOfCType: @encode(int) + at: &class_version + withName: NULL]; + + /* xxx should do classname substitution, + ala decodeClassName:intoClassName: here. */ + + ret = objc_lookup_class (class_name); + /* Ensure that the [+initialize] method has been called for the + class by calling one of it's methods */ + if (ret != Nil) + ret = [ret class]; + if (ret == Nil) + [NSException raise: NSGenericException + format: @"Couldn't find class `%s'", class_name]; + if (class_get_version(ret) != class_version) + [NSException + raise: NSGenericException + format: @"Class version mismatch, executable %d != encoded %d", + class_get_version(ret), class_version]; + + { + unsigned xref; + xref = [self _coderCreateReferenceForConstPtr: ret]; + if (debug_coder) + fprintf(stderr, + "Decoder decoding registered class xref %u\n", xref); + } + objc_free (class_name); + break; + } + default: + [NSException raise: NSGenericException + format: @"unrecognized class tag = %d", (int)tag]; + } + [self decodeUnindent]; + return ret; +} + +- (const char *) decodeAtomicStringWithName: (NSString* *) name +{ + char *s; + /* xxx Add repeat-string-ptr checking here */ + [self notImplemented:_cmd]; + [self decodeValueOfCType:@encode(char*) at:&s withName:name]; + return s; +} + +- (SEL) decodeSelectorWithName: (NSString* *) name +{ + char tag; + SEL ret = NULL; + + [self decodeName:name]; + [self decodeIndent]; + tag = [self decodeTag]; + switch (tag) + { + case CODER_CONST_PTR_NULL: + break; + case CODER_CONST_PTR_REPEATED: + { + unsigned xref; + [self decodeValueOfCType: @encode(unsigned) + at: &xref + withName: NULL]; + ret = (SEL) [self _coderConstPtrAtReference: xref]; + if (!ret) + [NSException + raise: NSGenericException + format: @"repeated selector cross-reference number %u not found", + xref]; + break; + } + case CODER_CONST_PTR: + { + char *sel_name; + char *sel_types; + + [self decodeValueOfCType:@encode(char *) + at:&sel_name + withName:NULL]; + [self decodeValueOfCType:@encode(char *) + at:&sel_types + withName:NULL]; +#if NeXT_runtime + ret = sel_getUid(sel_name); +#else + if (!strcmp(sel_types, NO_SEL_TYPES)) + ret = sel_get_any_uid(sel_name); + else + ret = sel_get_typed_uid(sel_name, sel_types); +#endif + if (!ret) + [NSException raise: NSGenericException + format: @"Could not find selector (%s) with types [%s]", + sel_name, sel_types]; +#if ! NeXT_runtime + if (strcmp(sel_types, NO_SEL_TYPES) + && !(sel_types_match(sel_types, ret->sel_types))) + [NSException + raise: NSGenericException + format: @"ObjC runtime didn't provide SEL with matching type"]; +#endif + { + unsigned xref; + xref = [self _coderCreateReferenceForConstPtr: ret]; + if (debug_coder) + fprintf(stderr, + "Decoder decoding registered sel xref %u\n", xref); + } + objc_free(sel_name); + objc_free(sel_types); + break; + } + default: + [NSException raise: NSGenericException + format: @"unrecognized selector tag = %d", (int)tag]; + } + [self decodeUnindent]; + return ret; +} + + +- (void) startDecodingInterconnectedObjects +{ + interconnect_stack_height++; + [self _coderPushRootObjectTable]; + [self _coderPushForwardObjectTable]; +} + +- (void) finishDecodingInterconnectedObjects +{ + NSParameterAssert (interconnect_stack_height); + + /* xxx This might not be the right thing to do; perhaps we should do + this finishing up work at the end of each nested call, not just + at the end of all nested calls. + However, then we might miss some forward references that we could + have resolved otherwise. */ + if (--interconnect_stack_height) + return; + + /* xxx fix the use of _coderPopForwardObjectTable and + _coderPopRootObjectTable. */ + +#if 0 /* Actually, we do this below in -decodeObjectAt:withName: */ + /* Send "-awakeAfterUsingCoder:" to all the objects that were read */ + { + SEL awake_sel = sel_get_any_uid("awakeAfterUsingCoder:"); + if (awake_sel) + { + int i; + id table = [self _coderTopRootObjectTable]; + + /* Loop through all objects that we decoded by this Decoder */ + for (i = [table count]-1; i >= 0; i--) + { + id o = [table objectAtIndex: i]; + if (__objc_responds_to(o, awake_sel)) + { + replacement_obj = + (*objc_msg_lookup(e.id_u,awake_sel))(o, awake_sel, self); + /* xxx Make the replacement in the decoder's object tables. */ + } + } + } + } +#endif + + /* resolve object forward references */ + [self _coderResolveTopForwardReferences]; + [self _coderPopForwardObjectTable]; + + [self _coderPopRootObjectTable]; +} + +- (void) _decodeRootObjectAt: (id*)ret withName: (NSString* *) name +{ + [self startDecodingInterconnectedObjects]; + [self decodeObjectAt:ret withName:name]; + [self finishDecodingInterconnectedObjects]; +} + + +- (void) decodeValueOfObjCType: (const char*)type + at: (void*)d + withName: (NSString* *)namePtr +{ + switch (*type) + { + case _C_CLASS: + { + [self decodeName:namePtr]; + *(id*)d = [self decodeClass]; + break; + } + case _C_ATOM: + *(const char**)d = [self decodeAtomicStringWithName:namePtr]; + break; + case _C_SEL: + *(SEL*)d = [self decodeSelectorWithName:namePtr]; + break; + case _C_ID: + [self decodeObjectAt:d withName:namePtr]; + break; + default: + [self decodeValueOfCType:type at:d withName:namePtr]; + } + /* xxx We need to catch unions and make a sensible error message */ +} + +- (BOOL) _createReferenceBeforeInit +{ + return NO; +} + +/* This is the designated (and one-and-only) object decoder */ +- (void) decodeObjectAt: (id*) anObjPtr withName: (NSString* *) name +{ + unsigned char tag; + unsigned fref = 0; + id dummy_object; + + /* Sometimes the user wants to decode an object, but doesn't care to + have a pointer to it, (LinkedList elements, for example). In + this case, the user can pass in NULL for anObjPtr, and all will + be safe. */ + if (!anObjPtr) + anObjPtr = &dummy_object; + + [self decodeName:name]; + [self decodeIndent]; + tag = [self decodeTag]; + switch (tag) + { + case CODER_OBJECT_NIL: + *anObjPtr = nil; + break; + case CODER_OBJECT_CLASS: + *anObjPtr = [self decodeClass]; + break; + case CODER_OBJECT_FORWARD_REFERENCE: + { + if (!DOING_ROOT_OBJECT) + [NSException + raise: NSGenericException + format: @"can't decode forward reference when not decoding " + @"a root object"]; + [self decodeValueOfCType: @encode(unsigned) + at: &fref + withName: NULL]; + /* The user doesn't need the object pointer anyway, don't record + it in the table. */ + if (anObjPtr == &dummy_object) + break; + [self _coderAssociateForwardReference: fref + withObjectAddress: anObjPtr]; + break; + } + case CODER_OBJECT: + { + Class object_class; + SEL new_sel = sel_get_any_uid ("newWithCoder:"); + Method* new_method; + BOOL create_ref_before_init = [self _createReferenceBeforeInit]; + /* Initialize this to <0 so we can tell below if it's been set */ + int xref = -1; + + [self decodeIndent]; + object_class = [self decodeClass]; + /* xxx Should change the runtime. + class_get_class_method should take the class as its first + argument, not the metaclass! */ + new_method = class_get_class_method(class_get_meta_class(object_class), + new_sel); + if (new_method && !create_ref_before_init) + *anObjPtr = (*(new_method->method_imp))(object_class, new_sel, self); + else + { + SEL init_sel = sel_get_any_uid ("initWithCoder:"); + Method *init_method = + class_get_instance_method (object_class, init_sel); + /* xxx Or should I send +alloc? */ + *anObjPtr = (id) NSAllocateObject (object_class, 0, zone); + if (create_ref_before_init) + xref = [self _coderInternalCreateReferenceForObject: *anObjPtr]; + if (init_method) + *anObjPtr = + (*(init_method->method_imp))(*anObjPtr, init_sel, self); + /* xxx else what, error? */ + } + + /* Send -awakeAfterUsingCoder: */ + /* xxx Unknown whether -awakeAfterUsingCoder: should be sent here, or + when Decoder is deallocated, or after a root object is finished + decoding. */ + /* NOTE: Use of this with the NeXT archiving methods is + tricky, because if [*anObj initWithCoder:] creates any + objects that references *anObj, and if [*anObj + awakeAfterUsingCoder:] replaces itself, then the + subobject's references will not be to the replacement. + There is no way to magically fix this circular dependancy; + users must be aware. We should just make sure we require + the same cautions as NeXT's implementation. Note that, with + the GNU archiving methods, this problem doesn't occur because + we don't register the object until after it has been fully + initialized and awakened. */ + { + SEL awake_sel = sel_get_any_uid ("awakeAfterUsingCoder:"); + IMP awake_imp = objc_msg_lookup (*anObjPtr, awake_sel); + id replacement; + + if (awake_imp) + { + replacement = (*awake_imp) (*anObjPtr, awake_sel, self); + if (replacement != *anObjPtr) + { + if (xref > 0) + [self _coderInternalSubstituteObject: replacement + atReference: xref]; + *anObjPtr = replacement; + } + } + } + + [self decodeUnindent]; + + /* If this was a CODER_OBJECT_FORWARD_SATISFIER, then remember it. */ + [self decodeValueOfCType: @encode(unsigned) + at: &fref + withName: NULL]; + if (fref) + { + NSAssert (!create_ref_before_init, + @"You are trying to decode an object with the non-GNU\n" + @"OpenStep-style forward references, but the object's\n" + @"decoding mechanism wants to use GNU features."); + [self _coderSatisfyForwardReference: fref withObject: *anObjPtr]; + } + + /* Would get error here with Connection-wide object references + because addProxy gets called in +newRemote:connection: */ + if (!create_ref_before_init) + { + unsigned xref = + [self _coderInternalCreateReferenceForObject: *anObjPtr]; + if (debug_coder) + fprintf(stderr, + "Decoder decoding registered class xref %u\n", xref); + } + break; + } + case CODER_OBJECT_ROOT: + { + [self _decodeRootObjectAt: anObjPtr withName: name]; + break; + } + case CODER_OBJECT_REPEATED: + { + unsigned xref; + + [self decodeValueOfCType: @encode(unsigned) + at: &xref + withName: NULL]; + *anObjPtr = [[self _coderObjectAtReference: xref] retain]; + if (!*anObjPtr) + [NSException + raise: NSGenericException + format: @"repeated object cross-reference number %u not found", + xref]; + break; + } + default: + [NSException raise: NSGenericException + format: @"unrecognized object tag = %d", (int)tag]; + } + [self decodeUnindent]; +} + + +- (void) decodeWithName: (NSString* *)name + valuesOfObjCTypes: (const char *)types, ... +{ + va_list ap; + + [self decodeName:name]; + va_start(ap, types); + while (*types) + { + [self decodeValueOfObjCType:types + at:va_arg(ap, void*) + withName:NULL]; + types = objc_skip_typespec(types); + } + va_end(ap); +} + +- (void) decodeValueOfObjCTypes: (const char *)types + at: (void *)d + withName: (NSString* *)name +{ + [self decodeName:name]; + while (*types) + { + [self decodeValueOfObjCType:types + at:d + withName:NULL]; + types = objc_skip_typespec(types); + } +} + +- (void) decodeArrayOfObjCType: (const char *)type + count: (unsigned)c + at: (void *)d + withName: (NSString* *) name +{ + int i; + int offset = objc_sizeof_type(type); + char *where = d; + + [self decodeName:name]; + for (i = 0; i < c; i++) + { + [self decodeValueOfObjCType:type + at:where + withName:NULL]; + where += offset; + } +} + +- (void) decodeIndent +{ + [cstream decodeIndent]; +} + +- (void) decodeUnindent +{ + [cstream decodeUnindent]; +} + +- (void) decodeName: (NSString* *)n +{ + [cstream decodeName: n]; +} + + ++ (NSString*) classNameDecodedForArchiveClassName: (NSString*) inArchiveName +{ + [self notImplemented:_cmd]; + return nil; +} + ++ (void) decodeClassName: (NSString*) inArchiveName + asClassName:(NSString *)trueName +{ + [self notImplemented:_cmd]; +} + + +/* Managing Zones */ + +- (NSZone*) objectZone +{ + return zone; +} + +- (void) setObjectZone: (NSZone*)z +{ + zone = z; +} + +- (void) dealloc +{ + if (xref_2_object) [xref_2_object release]; + if (xref_2_object_root) [xref_2_object_root release]; + if (xref_2_const_ptr) NSFreeMapTable (xref_2_const_ptr); + if (fref_2_object) NSFreeMapTable (fref_2_object); + if (address_2_fref) NSFreeMapTable (address_2_fref); + [super dealloc]; +} + +@end diff --git a/Old/DelegatePool.h b/Old/DelegatePool.h new file mode 100644 index 000000000..d385e5771 --- /dev/null +++ b/Old/DelegatePool.h @@ -0,0 +1,74 @@ +/* Interface for Objective-C "collection of delegates" object + Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: May 1993 + + 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. +*/ + +/* Using this object, a delegator can have an arbitrary number of + delegates. Send a message to this object and the message will get + forwarded to the delegates on the list. */ + +#ifndef __DelegatePool_h_GNUSTEP_BASE_INCLUDE +#define __DelegatePool_h_GNUSTEP_BASE_INCLUDE + +#include + +/* Available sending behaviors */ +enum DelegatePoolSendBehavior {SEND_TO_ALL = 0, + SEND_TO_FIRST_RESPONDER, + SEND_UNTIL_YES, + SEND_UNTIL_NO}; + +@interface DelegatePool +{ + struct objc_class *isa; + @public + unsigned char _send_behavior; + Array *_list; + BOOL _last_message_had_receivers; +} + +// CREATING AND FREEING; ++ alloc; ++ new; +- init; +- (void) dealloc; + +// MANIPULATING COLLECTION OF DELEGATES; +- (void) delegatePoolAddObject: anObject; +- (void) delegatePoolAddObjectIfAbsent: anObject; +- (void) delegatePoolRemoveObject: anObject; +- (BOOL) delegatePoolIncludesObject: anObject; +- delegatePoolCollection; +- (unsigned char) delegatePoolSendBehavior; +- (void) delegatePoolSetSendBehavior: (unsigned char)b; + +// FOR PASSING ALL OTHER MESSAGES TO DELEGATES; +// RETURNS 0 IF NO OBJECTS RESPOND; +- forward:(SEL)aSel :(arglist_t)argFrame; + +// FOR FINDING OUT IF ANY OBJECTS IN THE POOL RESPONDED TO THE LAST MSG; +/* This method is bad because it won't be thread-safe---it may + go away in the future. */ +- (BOOL) delegatePoolLastMessageHadReceivers; + +@end + +#endif /* __DelegatePool_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/DelegatePool.m b/Old/DelegatePool.m new file mode 100644 index 000000000..b2d33c6e4 --- /dev/null +++ b/Old/DelegatePool.m @@ -0,0 +1,210 @@ +/* Implementation of Objective-C "collection of delegates" object + Copyright (C) 1993,1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + This file is part of the GNU Objective-C Collection 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. + */ + +#include +#include +#include + +@implementation DelegatePool + ++ (void) initialize +{ + return; +} + ++ alloc +{ + return (id)class_create_instance(self); +} + ++ new +{ + return [[self alloc] init]; +} + +/* This is the designated initializer for this class. */ +- init +{ + _list = [[Array alloc] init]; + _send_behavior = SEND_TO_ALL; + _last_message_had_receivers = NO; + return self; +} + +/* Archiving must mimic the above designated initializer */ + +- (void) encodeWithCoder: anEncoder +{ + [anEncoder encodeValueOfCType:@encode(unsigned char) + at:&_send_behavior + withName:@"DelegatePool Send Behavior"]; + [anEncoder encodeObject:_list + withName:@"DelegatePool Collection of Delegates"]; +} + ++ newWithCoder: aDecoder +{ + /* xxx Should be: + DelegatePool *n = NSAllocateObject(self, 0, [aDecoder objectZone]); */ + DelegatePool *n = (id) NSAllocateObject(self, 0, NSDefaultMallocZone()); + [aDecoder decodeValueOfCType:@encode(unsigned char) + at:&(n->_send_behavior) + withName:NULL]; + [aDecoder decodeObjectAt:&(n->_list) + withName:NULL]; + return n; +} + + +- write: (TypedStream*)aStream +{ + objc_write_type(aStream, @encode(unsigned char), &_send_behavior); + objc_write_object(aStream, _list); + return self; +} + +- read: (TypedStream*)aStream +{ + objc_write_type(aStream, @encode(unsigned char), &_send_behavior); + objc_read_object(aStream, &_list); + return self; +} + + +- (void) dealloc +{ + [_list release]; +#if NeXT_runtime + object_dispose((Object*)self); +#else + NSDeallocateObject((NSObject*)self); +#endif +} + + +// MANIPULATING COLLECTION OF DELEGATES; + +- (void) delegatePoolAddObject: anObject +{ + [_list addObject: anObject]; +} + +- (void) delegatePoolAddObjectIfAbsent: anObject +{ + [_list addObjectIfAbsent: anObject]; +} + +- (void) delegatePoolRemoveObject: anObject +{ + [_list removeObject:anObject]; +} + +- (BOOL) delegatePoolIncludesObject: anObject +{ + return [_list containsObject:anObject]; +} + +- delegatePoolCollection +{ + return _list; +} + +- (unsigned char) delegatePoolSendBehavior +{ + return _send_behavior; +} + +- (void) delegatePoolSetSendBehavior: (unsigned char)b +{ + _send_behavior = b; +} + +- (BOOL) delegatePoolLastMessageHadReceivers +{ + return _last_message_had_receivers; +} + +// FOR PASSING ALL OTHER MESSAGES TO DELEGATES; + +- forward: (SEL)aSel :(arglist_t)argFrame +{ + void *ret = 0; + id delegate; + + _last_message_had_receivers = NO; + switch (_send_behavior) + { + case SEND_TO_ALL: + FOR_ARRAY(_list, delegate) + { + if ([delegate respondsTo:aSel]) + { + ret = [delegate performv:aSel :argFrame]; + _last_message_had_receivers = YES; + } + } + END_FOR_ARRAY (_list); + break; + + case SEND_TO_FIRST_RESPONDER: + FOR_ARRAY(_list, delegate) + { + if ([delegate respondsTo:aSel]) + { + _last_message_had_receivers = YES; + return [delegate performv:aSel :argFrame]; + } + } + END_FOR_ARRAY (_list); + break; + + case SEND_UNTIL_YES: + FOR_ARRAY(_list, delegate) + { + if ([delegate respondsTo:aSel]) + { + _last_message_had_receivers = YES; + if ((ret = [delegate performv:aSel :argFrame])) + return ret; + } + } + END_FOR_ARRAY (_list); + break; + + case SEND_UNTIL_NO: + FOR_ARRAY(_list, delegate) + { + if ([delegate respondsTo:aSel]) + { + _last_message_had_receivers = YES; + if (!(ret = [delegate performv:aSel :argFrame])) + return ret; + } + } + END_FOR_ARRAY (_list); + break; + } + return ret; +} + +@end diff --git a/Old/Dictionary.h b/Old/Dictionary.h new file mode 100644 index 000000000..42a9b064e --- /dev/null +++ b/Old/Dictionary.h @@ -0,0 +1,40 @@ +/* Interface for Objective-C Dictionary collection object + Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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 __Dictionary_h_GNUSTEP_BASE_INCLUDE +#define __Dictionary_h_GNUSTEP_BASE_INCLUDE + +#include +#include + +@interface Dictionary : KeyedCollection +{ + NSMapTable *_contents_hash; +} + +- initWithCapacity: (unsigned)aCapacity; + +@end + +#endif /* __Dictionary_h_GNUSTEP_BASE_INCLUDE */ + diff --git a/Old/Dictionary.m b/Old/Dictionary.m new file mode 100644 index 000000000..c5db64ecf --- /dev/null +++ b/Old/Dictionary.m @@ -0,0 +1,209 @@ +/* Implementation for Objective-C Dictionary collection object + Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: May 1993 + + 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. +*/ + +#include +#include +#include +#include + +#define DEFAULT_DICTIONARY_CAPACITY 32 + +@implementation Dictionary + +// MANAGING CAPACITY; + +/* Eventually we will want to have better capacity management, + potentially keep default capacity as a class variable. */ + ++ (unsigned) defaultCapacity +{ + return DEFAULT_DICTIONARY_CAPACITY; +} + +// INITIALIZING; + +/* This is the designated initializer of this class */ +- initWithCapacity: (unsigned)cap +{ + _contents_hash = NSCreateMapTable (NSObjectMapKeyCallBacks, + NSObjectMapValueCallBacks, + cap); + return self; +} + +/* Override the KeyedCollection designated initializer */ +- initWithObjects: (id*)objects forKeys: (id*)keys count: (unsigned)c +{ + [self initWithCapacity: c]; + while (c--) + [self putObject: objects[c] atKey: keys[c]]; + return self; +} + +- init +{ + return [self initWithCapacity: DEFAULT_DICTIONARY_CAPACITY]; +} + +/* Archiving must mimic the above designated initializer */ + +- _initCollectionWithCoder: (id )coder +{ + _contents_hash = NSCreateMapTable (NSObjectMapKeyCallBacks, + NSObjectMapValueCallBacks, + 0); + return self; +} + +/* Empty copy must empty an allocCopy'ed version of self */ + +- emptyCopy +{ + Dictionary *copy = [super emptyCopy]; + copy->_contents_hash = NSCreateMapTable (NSObjectMapKeyCallBacks, + NSObjectMapValueCallBacks, + 0); + return copy; +} + +- (void) _collectionReleaseContents +{ + if (_contents_hash) { + NSFreeMapTable (_contents_hash); + _contents_hash = 0; + } +} + +- (void) dealloc +{ + [self _collectionReleaseContents]; + [super dealloc]; +} + +/* This must work without sending any messages to content objects */ +- (void) _collectionEmpty +{ + NSResetMapTable (_contents_hash); +} + + +// ADDING OR REPLACING; + +- (void) addObject: newObject +{ + [self shouldNotImplement: _cmd]; + /* or should I make up some default behavior here? + Base it on object conforming to protocol, perhaps */ +} + +- (void) putObject: newObject atKey: aKey +{ + NSMapInsert (_contents_hash, aKey, newObject); +} + + +// REMOVING; + +- (void) removeObjectAtKey: aKey +{ + NSMapRemove (_contents_hash, aKey); +} + +- (void) removeObject: oldObject +{ + /* xxx Could be more efficient! */ + int count = [self count]; + id keys_to_remove[count]; + int num_keys_to_remove = 0; + id o, k; + NSMapEnumerator me = NSEnumerateMapTable (_contents_hash); + + /* Find all the keys with corresponding objects that equal oldObject. */ + while (NSNextMapEnumeratorPair (&me, (void**)&k, (void**)&o)) + if ([oldObject isEqual: o]) + keys_to_remove[num_keys_to_remove++] = k; + /* Remove them. */ + while (num_keys_to_remove--) + [self removeObjectAtKey: keys_to_remove[num_keys_to_remove]]; +} + + +// GETTING ELEMENTS; + +- (NSArray*) allKeys +{ + return NSAllMapTableKeys(_contents_hash); +} + +- (NSArray*) allValues +{ + return NSAllMapTableValues(_contents_hash); +} + +- objectAtKey: aKey +{ + return NSMapGet (_contents_hash, aKey); +} + + + +// TESTING; + +- (BOOL) containsKey: aKey +{ + if (NSMapGet (_contents_hash, aKey)) + return YES; + else + return NO; +} + +- (unsigned) count +{ + return NSCountMapTable (_contents_hash); +} + +// ENUMERATIONS; + +- nextObjectAndKey: (id*)aKeyPtr withEnumState: (void**)enumState +{ + id o; + if (!NSNextMapEnumeratorPair (*enumState, (void**)aKeyPtr, (void**)&o)) + return NO_OBJECT; + return o; +} + +- (void*) newEnumState +{ + void *me; + + OBJC_MALLOC (me, NSMapEnumerator, 1); + *((NSMapEnumerator*)me) = NSEnumerateMapTable (_contents_hash); + return me; +} + +- (void) freeEnumState: (void**)enumState +{ + OBJC_FREE (*enumState); +} + +@end diff --git a/Old/Encoder.m b/Old/Encoder.m new file mode 100644 index 000000000..63d9ac569 --- /dev/null +++ b/Old/Encoder.m @@ -0,0 +1,883 @@ +/* Abstract class for writing objects to a stream + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: February 1996, with core from Coder, created 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int default_format_version; +static id default_stream_class; +static id default_cstream_class; +#define DEFAULT_DEFAULT_FORMAT_VERSION 0 + +static int debug_coder = 0; + + +/* xxx For experimentation. The function in objc-api.h doesn't always + work for objects; it sometimes returns YES for an instance. */ +/* But, metaclasses return YES too? */ +static BOOL +my_object_is_class(id object) +{ + if (object != nil +#if NeXT_runtime + && CLS_ISMETA(((Class)object)->isa) + && ((Class)object)->isa != ((Class)object)->isa) +#else + && CLS_ISMETA(((Class)object)->class_pointer) + && ((Class)object)->class_pointer != ((Class)object)->class_pointer) +#endif + return YES; + else + return NO; +} + + +@implementation Encoder + ++ (void) initialize +{ + if (self == [Encoder class]) + { + /* This code has not yet been ported to machines for which + a pointer is not the same size as an int. */ + NSAssert(sizeof(void*) == sizeof(unsigned), + @"Pointer and int are different sizes"); + + /* Initialize some defaults. */ + default_stream_class = [MemoryStream class]; + default_cstream_class = [BinaryCStream class]; + default_format_version = DEFAULT_DEFAULT_FORMAT_VERSION; + } +} + + +/* Default format version, Stream and CStream class handling. */ + ++ (int) defaultFormatVersion +{ + return default_format_version; +} + ++ (void) setDefaultFormatVersion: (int)f +{ + default_format_version = f; +} + ++ (void) setDefaultCStreamClass: sc +{ + default_cstream_class = sc; +} + ++ defaultCStreamClass +{ + return default_cstream_class; +} + ++ (void) setDefaultStreamClass: sc +{ + default_stream_class = sc; +} + ++ defaultStreamClass +{ + return default_stream_class; +} + +/* xxx This method interface may change in the future. */ +- (const char *) defaultDecoderClassname +{ + return "Unarchiver"; +} + + +/* Signature Handling. */ + +- (void) writeSignature +{ + /* Careful: the string should not contain newlines. */ + [[cstream stream] writeFormat: SIGNATURE_FORMAT_STRING, + WRITE_SIGNATURE_FORMAT_ARGS]; +} + + + +/* This is the designated initializer for this class. */ +- initForWritingToStream: (id ) s + withFormatVersion: (int) version + cStreamClass: (Class) cStreamClass + cStreamFormatVersion: (int) cStreamFormatVersion +{ + [super _initWithCStream: [[cStreamClass alloc] + initForWritingToStream: s + withFormatVersion: cStreamFormatVersion] + formatVersion: version]; + [cstream release]; + in_progress_table = NULL; + object_2_xref = NULL; + object_2_fref = NULL; + const_ptr_2_xref = NULL; + fref_counter = 0; + [self writeSignature]; + return self; +} + +/* ..Writing... methods */ + +- initForWritingToStream: (id ) s + withCStreamClass: (Class) cStreamClass +{ + return [self initForWritingToStream: s + withFormatVersion: DEFAULT_DEFAULT_FORMAT_VERSION + cStreamClass: cStreamClass + cStreamFormatVersion: [cStreamClass defaultFormatVersion]]; +} + +- initForWritingToStream: (id ) s +{ + return [self initForWritingToStream: s + withCStreamClass: [[self class] defaultCStreamClass]]; +} + +- initForWritingToFile: (NSString*) filename + withFormatVersion: (int) version + cStreamClass: (Class) cStreamClass + cStreamFormatVersion: (int) cStreamFormatVersion +{ + return [self initForWritingToStream: [StdioStream + streamWithFilename: filename + fmode: "w"] + withFormatVersion: version + cStreamClass: cStreamClass + cStreamFormatVersion: cStreamFormatVersion]; +} + +- initForWritingToFile: (NSString*) filename + withCStreamClass: (Class) cStreamClass +{ + return [self initForWritingToStream: [StdioStream + streamWithFilename: filename + fmode: "w"] + withCStreamClass: cStreamClass]; +} + +- initForWritingToFile: (NSString*) filename +{ + return [self initForWritingToStream: + [StdioStream streamWithFilename: filename + fmode: "w"]]; +} + ++ newWritingToStream: (id )s +{ + return [[self alloc] initForWritingToStream: s]; +} + ++ newWritingToFile: (NSString*)filename +{ + return [self newWritingToStream: + [StdioStream streamWithFilename: filename + fmode: "w"]]; +} + ++ (BOOL) encodeRootObject: anObject + withName: (NSString*) name + toStream: (id )stream +{ + id c = [[self alloc] initForWritingToStream: stream]; + [c encodeRootObject: anObject withName: name]; + [c close]; + [c release]; + return YES; +} + ++ (BOOL) encodeRootObject: anObject + withName: (NSString*) name + toFile: (NSString*) filename +{ + return [self encodeRootObject: anObject + withName: name + toStream: [StdioStream streamWithFilename: filename + fmode: "w"]]; +} + + +/* Functions and methods for keeping cross-references + so objects aren't written/read twice. */ + +/* These _coder... methods may be overriden by subclasses so that + cross-references can be kept differently. + over again. +*/ +- (unsigned) _coderCreateReferenceForObject: anObj +{ + unsigned xref; + if (!object_2_xref) + { + object_2_xref = + NSCreateMapTable (NSNonOwnedPointerOrNullMapKeyCallBacks, + NSIntMapValueCallBacks, 0); + } + xref = NSCountMapTable (object_2_xref) + 1; + NSMapInsert (object_2_xref, anObj, (void*)xref); + return xref; +} + +- (unsigned) _coderReferenceForObject: anObject +{ + if (object_2_xref) + return (unsigned) NSMapGet (object_2_xref, anObject); + else + return 0; +} + + +/* Methods for handling constant pointers */ +/* By overriding the next three methods, subclasses can change the way + that const pointers (like SEL, Class, Atomic strings, etc) are + archived. */ + +- (unsigned) _coderCreateReferenceForConstPtr: (const void*)ptr +{ + unsigned xref; + if (!const_ptr_2_xref) + const_ptr_2_xref = + NSCreateMapTable (NSNonOwnedPointerOrNullMapKeyCallBacks, + NSIntMapValueCallBacks, 0); + + xref = NSCountMapTable (const_ptr_2_xref) + 1; + NSAssert (! NSMapGet (const_ptr_2_xref, (void*)xref), @"xref already in Map"); + NSMapInsert (const_ptr_2_xref, ptr, (void*)xref); + return xref; +} + +- (unsigned) _coderReferenceForConstPtr: (const void*)ptr +{ + if (const_ptr_2_xref) + return (unsigned) NSMapGet (const_ptr_2_xref, ptr); + else + return 0; +} + + +/* Methods for forward references */ + +- (unsigned) _coderCreateForwardReferenceForObject: anObject +{ + unsigned fref; + if (!object_2_fref) + object_2_fref = + NSCreateMapTable (NSNonOwnedPointerOrNullMapKeyCallBacks, + NSIntMapValueCallBacks, 0); + fref = ++fref_counter; + NSAssert ( ! NSMapGet (object_2_fref, anObject), @"anObject already in Map"); + NSMapInsert (object_2_fref, anObject, (void*)fref); + return fref; +} + +- (unsigned) _coderForwardReferenceForObject: anObject +{ + /* This method must return 0 if it's not there. */ + if (!object_2_fref) + return 0; + return (unsigned) NSMapGet (object_2_fref, anObject); +} + +- (void) _coderRemoveForwardReferenceForObject: anObject +{ + NSMapRemove (object_2_fref, anObject); +} + + +/* This is the Coder's interface to the over-ridable + "_coderPutObject:atReference" method. Do not override it. It + handles the root_object_table. */ + +- (void) _coderInternalCreateReferenceForObject: anObj +{ + [self _coderCreateReferenceForObject: anObj]; +} + + +/* Handling the in_progress_table. These are called before and after + the actual object (not a forward or backward reference) is encoded. + + One of these objects should also call + -_coderInternalCreateReferenceForObject:. GNU archiving calls it + in the first, in order to force forward references to objects that + are in progress; this allows for -initWithCoder: methods that + deallocate self, and return another object. OpenStep-style coding + calls it in the second, meaning that we never create forward + references to objects that are in progress; we encode a backward + reference to the in progress object, and assume that it will not + change location. */ + +- (void) _objectWillBeInProgress: anObj +{ + if (!in_progress_table) + in_progress_table = + /* This is "NonOwnedPointer", and not "Object", because + with "Object" we would get an infinite loop with distributed + objects when we try to put a Proxy in in the table, and + send the proxy the -hash method. */ + NSCreateMapTable (NSNonOwnedPointerMapKeyCallBacks, + NSIntMapValueCallBacks, 0); + NSMapInsert (in_progress_table, anObj, (void*)1); +} + +- (void) _objectNoLongerInProgress: anObj +{ + NSMapRemove (in_progress_table, anObj); + /* Register that we have encoded it so that future encoding can + do backward references properly. */ + [self _coderInternalCreateReferenceForObject: anObj]; +} + + +/* Method for encoding things. */ + +- (void) encodeValueOfCType: (const char*)type + at: (const void*)d + withName: (NSString*)name +{ + [cstream encodeValueOfCType:type + at:d + withName:name]; +} + +- (void) encodeBytes: (const void *)b + count: (unsigned)c + withName: (NSString*)name +{ + /* xxx Is this what we want? + It won't be cleanly readable in TextCStream's. */ + [cstream encodeName: name]; + [[cstream stream] writeBytes: b length: c]; +} + + +- (void) encodeTag: (unsigned char)t +{ + if ([cstream respondsToSelector: @selector(encodeTag:)]) + [(id)cstream encodeTag:t]; + else + [self encodeValueOfCType:@encode(unsigned char) + at:&t + withName:@"Coder tag"]; +} + +- (void) encodeClass: aClass +{ + [self encodeIndent]; + if (aClass == Nil) + { + [self encodeTag: CODER_CLASS_NIL]; + } + else + { + /* xxx Perhaps I should do classname substitution here. */ + const char *class_name = class_get_class_name (aClass); + unsigned xref; + + /* Do classname substitution, ala encodeClassName:intoClassName */ + if (classname_2_classname) + { + char *subst_class_name = NSMapGet (classname_2_classname, + class_name); + if (subst_class_name) + { + class_name = subst_class_name; + aClass = objc_lookup_class (class_name); + } + } + + xref = [self _coderReferenceForConstPtr: aClass]; + if (xref) + { + /* It's already been encoded, so just encode the x-reference */ + [self encodeTag: CODER_CLASS_REPEATED]; + [self encodeValueOfCType: @encode(unsigned) + at: &xref + withName: @"Class cross-reference number"]; + } + else + { + /* It hasn't been encoded before; encode it. */ + int class_version = class_get_version (aClass); + + NSAssert (class_name, @"Class doesn't have a name"); + NSAssert (*class_name, @"Class name is empty"); + + [self encodeTag: CODER_CLASS]; + [self encodeValueOfCType: @encode(char*) + at: &class_name + withName: @"Class name"]; + [self encodeValueOfCType: @encode(int) + at: &class_version + withName: @"Class version"]; + [self _coderCreateReferenceForConstPtr: aClass]; + } + } + [self encodeUnindent]; + return; +} + +- (void) encodeAtomicString: (const char*) sp + withName: (NSString*) name +{ + /* xxx Add repeat-string-ptr checking here. */ + [self notImplemented:_cmd]; + [self encodeValueOfCType:@encode(char*) at:&sp withName:name]; +} + +- (void) encodeSelector: (SEL)sel withName: (NSString*) name +{ + [self encodeName:name]; + [self encodeIndent]; + if (sel == 0) + { + [self encodeTag: CODER_CONST_PTR_NULL]; + } + else + { + unsigned xref = [self _coderReferenceForConstPtr: sel]; + if (xref) + { + /* It's already been encoded, so just encode the x-reference */ + [self encodeTag: CODER_CONST_PTR_REPEATED]; + [self encodeValueOfCType: @encode(unsigned) + at: &xref + withName: @"SEL cross-reference number"]; + } + else + { + const char *sel_name; + const char *sel_types; + + [self encodeTag: CODER_CONST_PTR]; + + /* Get the selector name and type. */ + sel_name = sel_get_name(sel); +#if NeXT_runtime + sel_types = NO_SEL_TYPES; +#else + sel_types = sel_get_type(sel); +#endif +#if 1 /* xxx Yipes,... careful... */ + /* xxx Think about something like this. */ + if (!sel_types) + sel_types = + sel_get_type (sel_get_any_typed_uid (sel_get_name (sel))); +#endif + if (!sel_name || !*sel_name) + [NSException raise: NSGenericException + format: @"ObjC runtime didn't provide SEL name"]; + if (!sel_types || !*sel_types) + sel_types = NO_SEL_TYPES; + + [self _coderCreateReferenceForConstPtr: sel]; + [self encodeValueOfCType: @encode(char*) + at: &sel_name + withName: @"SEL name"]; + [self encodeValueOfCType: @encode(char*) + at: &sel_types + withName: @"SEL types"]; + if (debug_coder) + fprintf(stderr, "Coder encoding registered sel xref %u\n", xref); + } + } + [self encodeUnindent]; + return; +} + +- (void) encodeValueOfObjCType: (const char*) type + at: (const void*) d + withName: (NSString*) name +{ + switch (*type) + { + case _C_CLASS: + [self encodeName: name]; + [self encodeClass: *(id*)d]; + break; + case _C_ATOM: + [self encodeAtomicString: *(char**)d withName: name]; + break; + case _C_SEL: + { + [self encodeSelector: *(SEL*)d withName: name]; + break; + } + case _C_ID: + [self encodeObject: *(id*)d withName: name]; + break; + default: + [self encodeValueOfCType:type at:d withName:name]; + } +} + + +/* Methods for handling interconnected objects */ + +- (void) startEncodingInterconnectedObjects +{ + interconnect_stack_height++; +} + +- (void) finishEncodingInterconnectedObjects +{ + /* xxx Perhaps we should look at the forward references and + encode here any forward-referenced objects that haven't been + encoded yet. No---the current behavior implements NeXT's + -encodeConditionalObject: */ + NSParameterAssert (interconnect_stack_height); + interconnect_stack_height--; +} + +/* NOTE: Unlike NeXT's, this *can* be called recursively */ +- (void) encodeRootObject: anObj + withName: (NSString*)name +{ + [self encodeName: @"Root Object"]; + [self encodeIndent]; + [self encodeTag: CODER_OBJECT_ROOT]; + [self startEncodingInterconnectedObjects]; + [self encodeObject: anObj withName: name]; + [self finishEncodingInterconnectedObjects]; + [self encodeUnindent]; +} + + +/* These next three methods are the designated coder methods called when + we've determined that the object has not already been + encoded---we're not simply going to encode a cross-reference number + to the object, we're actually going to encode an object (either a + proxy to the object or the object itself). + + NSPortCoder overrides _doEncodeObject: in order to implement + the encoding of proxies. */ + +- (void) _doEncodeBycopyObject: anObj +{ + id encoded_object, encoded_class; + + /* Give the user the opportunity to substitute the class and object */ + /* xxx Is this the right place for this substitution? */ + if ([[self class] isKindOf: [NSCoder class]] + && ! [[self class] isKindOf: [NSArchiver class]]) + /* Make sure we don't do this for the Coder class, because + by default Coder should behave like NSArchiver. */ + { + encoded_object = [anObj replacementObjectForCoder: (NSCoder*)self]; + encoded_class = [encoded_object classForCoder]; + } + else + { + encoded_object = [anObj replacementObjectForArchiver: (NSArchiver*)self]; + encoded_class = [encoded_object classForArchiver]; + } + [self encodeClass: encoded_class]; + /* xxx We should make sure it responds to this selector! */ + [encoded_object encodeWithCoder: (id)self]; +} + +/* This method overridden by NSPortCoder */ +- (void) _doEncodeObject: anObj +{ + [self _doEncodeBycopyObject:anObj]; +} + +/* This method overridden by NSPortCoder */ +- (void) _doEncodeByrefObject: anObj +{ + [self _doEncodeObject: anObj]; +} + + +/* This is the designated object encoder */ +- (void) _encodeObject: anObj + withName: (NSString*) name + isBycopy: (BOOL) bycopy_flag + isByref: (BOOL) byref_flag + isForwardReference: (BOOL) forward_ref_flag +{ + [self encodeName:name]; + [self encodeIndent]; + if (!anObj) + { + [self encodeTag:CODER_OBJECT_NIL]; + } + else if (my_object_is_class(anObj)) + { + [self encodeTag: CODER_OBJECT_CLASS]; + [self encodeClass:anObj]; + } + else + { + unsigned xref = [self _coderReferenceForObject: anObj]; + if (xref) + { + /* It's already been encoded, so just encode the x-reference */ + [self encodeTag: CODER_OBJECT_REPEATED]; + [self encodeValueOfCType: @encode(unsigned) + at: &xref + withName: @"Object cross-reference number"]; + } + else if (forward_ref_flag + || (in_progress_table + && NSMapGet (in_progress_table, anObj))) + { + unsigned fref; + + /* We are going to encode a forward reference, either because + (1) our caller asked for it, or (2) we are in the middle + of encoding this object, and haven't finished encoding it yet. */ + /* Find out if it already has a forward reference number. */ + fref = [self _coderForwardReferenceForObject: anObj]; + if (!fref) + /* It doesn't, so create one. */ + fref = [self _coderCreateForwardReferenceForObject: anObj]; + [self encodeTag: CODER_OBJECT_FORWARD_REFERENCE]; + [self encodeValueOfCType: @encode(unsigned) + at: &fref + withName: @"Object forward cross-reference number"]; + } + else + { + /* No backward or forward references, we are going to encode + the object. */ + unsigned fref; + + /* Register the object as being in progress of encoding. In + OpenStep-style archiving, this method also calls + -_coderInternalCreateReferenceForObject:. */ + [self _objectWillBeInProgress: anObj]; + + /* Encode the object. */ + [self encodeTag: CODER_OBJECT]; + [self encodeIndent]; + if (bycopy_flag) + [self _doEncodeBycopyObject:anObj]; + else if (byref_flag) + [self _doEncodeByrefObject:anObj]; + else + [self _doEncodeObject:anObj]; + [self encodeUnindent]; + + /* Find out if this object satisfies any forward references, + and encode either the forward reference number, or a + zero. NOTE: This test is here, and not before the + _doEncode.., because the encoding of this object may, + itself, generate a "forward reference" to this object, + (ala the in_progress_table). That is, we cannot know + whether this object satisfies a forward reference until + after it has been encoded. */ + fref = [self _coderForwardReferenceForObject: anObj]; + if (fref) + { + /* It does satisfy a forward reference; write the forward + reference number, so the decoder can know. */ + [self encodeValueOfCType: @encode(unsigned) + at: &fref + withName: @"Object forward cross-reference number"]; + /* Remove it from the forward reference table, since we'll never + have another forward reference for this object. */ + [self _coderRemoveForwardReferenceForObject: anObj]; + } + else + { + /* It does not satisfy any forward references. Let the + decoder know this by encoding NULL. Note: in future + encoding we may have backward references to this + object, but we will never need forward references to + this object. */ + unsigned null_fref = 0; + [self encodeValueOfCType: @encode(unsigned) + at: &null_fref + withName: @"Object forward cross-reference number"]; + } + + /* We're done encoding the object, it's no longer in progress. + In GNU-style archiving, this method also calls + -_coderInternalCreateReferenceForObject:. */ + [self _objectNoLongerInProgress: anObj]; + } + } + [self encodeUnindent]; +} + +- (void) encodeObject: anObj + withName: (NSString*)name +{ + [self _encodeObject:anObj + withName:name + isBycopy:NO + isByref:NO + isForwardReference:NO]; +} + + +- (void) encodeBycopyObject: anObj + withName: (NSString*)name +{ + [self _encodeObject:anObj + withName:name + isBycopy:YES + isByref:NO + isForwardReference:NO]; +} + +- (void) encodeByrefObject: anObj + withName: (NSString*)name +{ + [self _encodeObject:anObj + withName:name + isBycopy:NO + isByref:YES + isForwardReference:NO]; +} + +- (void) encodeObjectReference: anObj + withName: (NSString*)name +{ + [self _encodeObject:anObj + withName:name + isBycopy:NO + isByref:NO + isForwardReference:YES]; +} + + + +- (void) encodeWithName: (NSString*)name + valuesOfObjCTypes: (const char *)types, ... +{ + va_list ap; + + [self encodeName:name]; + va_start(ap, types); + while (*types) + { + [self encodeValueOfObjCType:types + at:va_arg(ap, void*) + withName:@"Encoded Types Component"]; + types = objc_skip_typespec(types); + } + va_end(ap); +} + +- (void) encodeValueOfObjCTypes: (const char *)types + at: (const void *)d + withName: (NSString*)name +{ + [self encodeName:name]; + while (*types) + { + [self encodeValueOfObjCType:types + at:d + withName:@"Encoded Types Component"]; + types = objc_skip_typespec(types); + } +} + +- (void) encodeArrayOfObjCType: (const char *)type + count: (unsigned)c + at: (const void *)d + withName: (NSString*)name +{ + int i; + int offset = objc_sizeof_type(type); + const char *where = d; + + [self encodeName:name]; + for (i = 0; i < c; i++) + { + [self encodeValueOfObjCType:type + at:where + withName:@"Encoded Array Component"]; + where += offset; + } +} + +- (void) encodeIndent +{ + [cstream encodeIndent]; +} + +- (void) encodeUnindent +{ + [cstream encodeUnindent]; +} + +- (void) encodeName: (NSString*)n +{ + [cstream encodeName: n]; +} + + +/* Substituting Classes */ + +- (NSString*) classNameEncodedForTrueClassName: (NSString*) trueName +{ + [self notImplemented: _cmd]; + return nil; + +#if 0 + if (classname_2_classname) + return NSMapGet (classname_2_classname, [trueName cString]); + return trueName; +#endif +} + +- (void) encodeClassName: (NSString*) trueName + intoClassName: (NSString*) inArchiveName +{ + [self notImplemented: _cmd]; + +#if 0 + /* The table should hold char*'s, not id's. */ + if (!classname_2_classname) + classname_2_classname = + NSCreateMapTable (NSObjectsMapKeyCallBacks, + NSObjectsMapValueCallBacks, 0); + NSMapInsert (classname_2_classname, trueName, inArchiveName); +#endif +} + +- (void) dealloc +{ + if (in_progress_table) NSFreeMapTable (in_progress_table); + if (object_2_xref) NSFreeMapTable (object_2_xref); + if (object_2_fref) NSFreeMapTable (object_2_fref); + if (const_ptr_2_xref) NSFreeMapTable (const_ptr_2_xref); + if (classname_2_classname) NSFreeMapTable (classname_2_classname); + [super dealloc]; +} + +@end diff --git a/Old/Enumerating.h b/Old/Enumerating.h new file mode 100644 index 000000000..a294be5da --- /dev/null +++ b/Old/Enumerating.h @@ -0,0 +1,36 @@ +/* Protocol for GNU Objective C invocations + Copyright (C) 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: February 1996 + + 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 __Enumerating_h__GNUSTEP_BASE_INCLUDE +#define __Enumerating_h__GNUSTEP_BASE_INCLUDE + +#include +@protocol Enumerating + +- initWithCollection: aCollection; +- nextObject; + +@end + +#endif /* __Enumerating_h__GNUSTEP_BASE_INCLUDE */ + diff --git a/Old/GapArray.h b/Old/GapArray.h new file mode 100644 index 000000000..5edbd329e --- /dev/null +++ b/Old/GapArray.h @@ -0,0 +1,38 @@ +/* Interface for Objective-C GapArray collection object + Copyright (C) 1993,1994 Free Software Foundation, Inc. + + Written by: Kresten Krab Thorup + Dept. of Mathematics and Computer Science, Aalborg U., Denmark + + 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 __GapArray_h_GNUSTEP_BASE_INCLUDE +#define __GapArray_h_GNUSTEP_BASE_INCLUDE + +#include + +@interface GapArray : Array +{ + @public + unsigned _gap_start; /* start of gap */ + unsigned _gap_size; /* size of gap */ +} + +@end + +#endif /* __GapArray_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/GapArray.m b/Old/GapArray.m new file mode 100644 index 000000000..f2f9ce017 --- /dev/null +++ b/Old/GapArray.m @@ -0,0 +1,144 @@ +/* Implementation for Objective-C GapArray collection object + Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Kresten Krab Thorup + Dept. of Mathematics and Computer Science, Aalborg U., Denmark + + Overhauled by: Andrew Kachites McCallum + + 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. +*/ + + +#include +#include +#include + +@implementation GapArray + +/* This is the designated initializer of this class */ +/* Override designated initializer of superclass */ +- initWithCapacity: (unsigned)aCapacity +{ + [super initWithCapacity: aCapacity]; + _gap_start = 0; + _gap_size = aCapacity; + return self; +} + +/* Archiving must mimic the above designated initializer */ + +- (void) encodeWithCoder: anEncoder +{ + [self notImplemented:_cmd]; +} + ++ newWithCoder: aDecoder +{ + [self notImplemented:_cmd]; + return self; +} + +/* Empty copy must empty an allocCopy'ed version of self */ + +- emptyCopy +{ + GapArray *copy = [super emptyCopy]; + copy->_gap_start = 0; + copy->_gap_size = copy->_capacity; + return copy; +} + +- (void) empty +{ + [super empty]; + _gap_start = 0; + _gap_size = _capacity; +} + +- (void) setCapacity: (unsigned)newCapacity +{ + if (newCapacity > _count) + { + gapMoveGapTo (self, _capacity-_gap_size); /* move gap to end */ + [super setCapacity: newCapacity]; /* resize */ + _gap_size = _capacity - _gap_start; + } +} + +- (void) removeObjectAtIndex: (unsigned)index +{ + CHECK_INDEX_RANGE_ERROR(index, _count); + [_contents_array[GAP_TO_BASIC (index)] release]; + gapFillHoleAt (self, index); + decrementCount(self); +} + +- objectAtIndex: (unsigned)index +{ + CHECK_INDEX_RANGE_ERROR(index, _count); + return _contents_array[GAP_TO_BASIC(index)]; +} + +- (void) appendObject: newObject +{ + incrementCount(self); + [newObject retain]; + gapMakeHoleAt (self, _count-1); + _contents_array[_count-1] = newObject; +} + +- (void) prependObject: newObject +{ + incrementCount(self); + [newObject retain]; + gapMakeHoleAt (self, 0); + _contents_array[0] = newObject; +} + +- (void) insertObject: newObject atIndex: (unsigned)index +{ + CHECK_INDEX_RANGE_ERROR(index, _count+1); + incrementCount(self); + [newObject retain]; + gapMakeHoleAt (self, index); + _contents_array[index] = newObject; +} + +- (void) replaceObjectAtIndex: (unsigned)index withObject: newObject +{ + CHECK_INDEX_RANGE_ERROR(index, _count); + [newObject retain]; + [_contents_array[GAP_TO_BASIC(index)] release]; + _contents_array[GAP_TO_BASIC(index)] = newObject; +} + +- (void) swapAtIndeces: (unsigned)index1 : (unsigned)index2 +{ + id tmp; + + CHECK_INDEX_RANGE_ERROR(index1, _count); + CHECK_INDEX_RANGE_ERROR(index2, _count); + index1 = GAP_TO_BASIC(index1); + index2 = GAP_TO_BASIC(index2); + tmp = _contents_array[index1]; + _contents_array[index1] = _contents_array[index2]; + _contents_array[index2] = tmp; +} + +@end + diff --git a/Old/GapArrayPrivate.h b/Old/GapArrayPrivate.h new file mode 100644 index 000000000..a20fcd87b --- /dev/null +++ b/Old/GapArrayPrivate.h @@ -0,0 +1,88 @@ +/* GapArray definitions for the use of subclass implementations + Copyright (C) 1993,1994 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + Copyright (C) 1993,1994 Kresten Krab Thorup + Dept. of Mathematics and Computer Science, Aalborg U., Denmark + + 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 __GapArrayPrivate_h_GNUSTEP_BASE_INCLUDE +#define __GapArrayPrivate_h_GNUSTEP_BASE_INCLUDE + +#include +#include + +#define GAP_TO_BASIC(INDEX) \ + ({ unsigned int __idx = (INDEX); \ + __idx >= self->_gap_start \ + ? __idx+self->_gap_size : __idx; }) + +#define BASIC_TO_GAP(INDEX) \ + ({ unsigned int __idx = (INDEX); \ + __idx < self->_gap_start \ + ? __idx : __idx-self->_gap_size; }) + +static inline void +gapMoveGapTo (GapArray* self, unsigned index) +{ + int i; + assert (index <= self->_capacity); + if (index < self->_gap_start) + { +#ifndef STABLE_MEMCPY + int b = index + self->_gap_size; + for (i = self->_gap_start + self->_gap_size - 1; i >= b; i--) + self->_contents_array[i] = self->_contents_array[i - self->_gap_size]; +#else + memcpy (self->_contents_array + index + self->_gap_size, + self->_contents_array + index, + self->_gap_start - index) +#endif + } + else + { +#ifndef STABLE_MEMCPY + for(i = self->_gap_start; i != index; i++) + self->_contents_array[i] = self->_contents_array[i + self->_gap_size]; +#else + memcpy (self->_contents_array + self->_gap_start, + self->_contents_array + self->_gap_start + self->_gap_size, + index - self->_gap_start); +#endif + } + self->_gap_start = index; +} + +static inline void +gapMakeHoleAt(GapArray *self, unsigned index) +{ + gapMoveGapTo (self, index); + self->_gap_start += 1; + self->_gap_size -= 1; +} + +static inline void +gapFillHoleAt(GapArray *self, unsigned index) +{ + gapMoveGapTo (self, index); + self->_gap_size += 1; +} + +#endif /* __GapArrayPrivate_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/Heap.h b/Old/Heap.h new file mode 100644 index 000000000..421ebe40e --- /dev/null +++ b/Old/Heap.h @@ -0,0 +1,36 @@ +/* Interface for Objective-C Heap collection object + Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: May 1993 + + 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 __Heap_h_GNUSTEP_BASE_INCLUDE +#define __Heap_h_GNUSTEP_BASE_INCLUDE + +#include + +@interface Heap : Array + +- (void) heapifyFromIndex: (unsigned)index; +- (void) heapify; + +@end + +#endif /* __Heap_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/Heap.m b/Old/Heap.m new file mode 100644 index 000000000..6dba19570 --- /dev/null +++ b/Old/Heap.m @@ -0,0 +1,102 @@ +/* Implementation for Objective-C Heap object + Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: May 1993 + + 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. +*/ + +/* This class could be improved by somehow making is a subclass of + IndexedCollection, but not OrderedCollection. */ + +#include +#include +#include + +#define HEAP_PARENT(i) (i/2) +#define HEAP_LEFT(i) (2 * i) +#define HEAP_RIGHT(i) ((2 * i) + 1) + +@implementation Heap + +/* We could take out the recursive call to make it a little more efficient */ +- (void) heapifyFromIndex: (unsigned)index +{ + unsigned right, left, largest; + id tmp; + + right = HEAP_RIGHT(index); + left = HEAP_LEFT(index); + if (left < _count + && [_contents_array[index] compare: _contents_array[left]] > 0) + largest = left; + else + largest = index; + if (right < _count + && [_contents_array[largest] compare: _contents_array[right]] > 0) + largest = right; + if (largest != index) + { + tmp = _contents_array[index]; + _contents_array[index] = _contents_array[largest]; + _contents_array[largest] = tmp; + [self heapifyFromIndex:largest]; + } +} + +- (void) heapify +{ + int i; + + // could use objc_msg_lookup here; + for (i = _count / 2; i >= 1; i--) + [self heapifyFromIndex:i]; +} + +- (void) removeFirstObject +{ + if (_count == 0) + return; + [_contents_array[0] release]; + _contents_array[0] = _contents_array[_count-1]; + decrementCount(self); + [self heapifyFromIndex:0]; +} + +- (void) addObject: newObject +{ + int i; + + incrementCount(self); + [newObject retain]; + for (i = _count-1; + i > 0 + && [newObject compare: _contents_array[HEAP_PARENT(i)]] < 0; + i = HEAP_PARENT(i)) + { + _contents_array[i] = _contents_array[HEAP_PARENT(i)]; + } + _contents_array[i] = newObject; +} + +- (id) minObject +{ + return [self firstObject]; +} + +@end diff --git a/Old/IndexedCollecting.h b/Old/IndexedCollecting.h new file mode 100644 index 000000000..145692be3 --- /dev/null +++ b/Old/IndexedCollecting.h @@ -0,0 +1,132 @@ +/* Protocol for Objective-C objects that hold elements accessible by index + Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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. +*/ + +/* The protocol inherits from the + protocol. + + The protocol defines the interface to a + collection of elements that are accessible by a key that is an index, + where the indeces in a collection are a contiguous series of unsigned + integers beginning at 0. This is the root of the protocol heirarchy + for all collections that hold their elements in some order. Elements + may be accessed, inserted, replaced and removed by their index. +*/ + +#ifndef __IndexedCollecting_h_GNUSTEP_BASE_INCLUDE +#define __IndexedCollecting_h_GNUSTEP_BASE_INCLUDE + +#include +#include + +#define IndexRange NSRange + +#define IndexRangeInside(RANGE1,RANGE2) \ + ({IndexRange __a=(RANGE1), __b=(RANGE2); \ + __a.start<=__b.start && __a.end>=__b.end;}) + + +@protocol ConstantIndexedCollecting + +// GETTING MEMBERS BY INDEX; +- objectAtIndex: (unsigned)index; +- firstObject; +- lastObject; + +// GETTING MEMBERS BY NEIGHBOR; +- successorOfObject: anObject; +- predecessorOfObject: anObject; + +// GETTING INDICES BY MEMBER; +- (unsigned) indexOfObject: anObject; +- (unsigned) indexOfObject: anObject inRange: (IndexRange)aRange; + +// TESTING; +- (BOOL) contentsEqualInOrder: (id )aColl; +- (int) compareInOrderContentsOf: (id )aCollection; +- (unsigned) indexOfFirstDifference: (id )aColl; +- (unsigned) indexOfFirstIn: (id )aColl; +- (unsigned) indexOfFirstNotIn: (id )aColl; + +// ENUMERATING; +- (id ) reverseObjectEnumerator; +- (void) withObjectsInRange: (IndexRange)aRange + invoke: (id )anInvocation; +- (void) withObjectsInReverseInvoke: (id )anInvocation; +- (void) withObjectsInReverseInvoke: (id )anInvocation + whileTrue:(BOOL *)flag; +- (void) makeObjectsPerformInReverse: (SEL)aSel; +- (void) makeObjectsPerformInReverse: (SEL)aSel withObject: argObject; + +// LOW-LEVEL ENUMERATING; +- prevObjectWithEnumState: (void**)enumState; + +@end + + +@protocol IndexedCollecting + +// REPLACING; +- (void) replaceObjectAtIndex: (unsigned)index with: newObject; + +// REMOVING; +- (void) removeObjectAtIndex: (unsigned)index; +- (void) removeFirstObject; +- (void) removeLastObject; +- (void) removeRange: (IndexRange)aRange; + +// SORTING; +- (void) sortContents; +- (void) sortAddObject: newObject; + +@end + +#define NO_INDEX NSNotFound + +/* xxx Fix this comment: */ + +/* Most methods in the KeyedCollecting protocol that mention a key are + duplicated in the IndexedCollecting protocol, with their names + modified to reflect that the "key" now must be an unsigned integer, + (an "index"). The programmer should be able to use either of the + corresponding method names to the same effect. + + The new methods are provided in the IndexedCollecting protocol for: + 1) Better type checking for when an unsigned int is required. + 2) More intuitive method names. + + IndexedCollecting KeyedCollecting + ---------------------------------------------------------------------- + insertObject:atIndex insertObject:atKey: + replaceObjectAtIndex:with: replaceObjectAtKey:with: + removeObjectAtIndex: removeObjectAtKey: + objectAtIndex: objectAtKey: + includesIndex: includesKey: + + insertElement:atIndex insertElement:atKey: + replaceElementAtIndex:with: replaceElementAtKey:with: + removeElementAtIndex: removeElementAtKey: + elementAtIndex: elementAtKey: + +*/ + +#endif /* __IndexedCollecting_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/IndexedCollection.h b/Old/IndexedCollection.h new file mode 100644 index 000000000..7250b25dc --- /dev/null +++ b/Old/IndexedCollection.h @@ -0,0 +1,110 @@ +/* Interface for Objective-C Sequential Collection object. + Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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 __IndexedCollection_h_GNUSTEP_BASE_INCLUDE +#define __IndexedCollection_h_GNUSTEP_BASE_INCLUDE + +#include +#include + +@interface ConstantIndexedCollection : ConstantCollection +@end + +@interface IndexedCollection : ConstantIndexedCollection +@end + +@interface ReverseEnumerator : Enumerator +@end + +/* Put this on category instead of class to avoid bogus complaint from gcc */ +@interface ConstantIndexedCollection (Protocol) +@end +@interface IndexedCollection (Protocol) +@end + +#define FOR_INDEXED_COLLECTION(ACOLL, ELT) \ +{ \ + void *_es = [ACOLL newEnumState]; \ + while ((ELT = [ACOLL nextObjectWithEnumState: &_es])) \ + { + +#define END_FOR_INDEXED_COLLECTION(ACOLL) \ + } \ + [ACOLL freeEnumState: &_es]; \ +} + +#define FOR_INDEXED_COLLECTION_REVERSE(ACOLL, ELT) \ +{ \ + void *_es = [ACOLL newEnumState]; \ + while ((ELT = [ACOLL prevObjectWithEnumState: &_es])) \ + { + +#define END_FOR_INDEXED_COLLECTION_REVERSE(ACOLL) \ + } \ + [ACOLL freeEnumState: &_es]; \ +} + +#define FOR_INDEXED_COLLECTION_WHILE_TRUE(ACOLL, ELT, FLAG) \ +{ \ + void *_es = [ACOLL newEnumState]; \ + while (FLAG && (ELT = [ACOLL nextObjectWithEnumState: &_es])) \ + { + +#define END_FOR_INDEXED_COLLECTION_WHILE_TRUE(ACOLL) \ + } \ + [ACOLL freeEnumState: &_es]; \ +} + + +/* The only subclassResponsibilities in IndexedCollection are: + + insertElement:atIndex: + removeElementAtIndex: + elementAtIndex: + + but subclass will want to override others as well in order to + increase efficiency. The following are especially important if + the subclass's implementation of "elementAtIndex:" is not efficient: + + replaceElementAtIndex:with: + swapAtIndeces:: + shallowCopyReplaceFrom:to:with: + sortAddElement:byCalling: + removeElement: + firstElement + lastElement + shallowCopyFrom:to: + withElementsCall:whileTrue: + withElementsInReverseCall:whileTrue: + + and perhaps: + + appendElement: + prependElement: + indexOfElement: + withElementsInReverseCall: + +*/ + + +#endif /* __IndexedCollection_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/IndexedCollection.m b/Old/IndexedCollection.m new file mode 100644 index 000000000..7d116db9d --- /dev/null +++ b/Old/IndexedCollection.m @@ -0,0 +1,466 @@ +/* Implementation for Objective-C IndexedCollection object + Copyright (C) 1993,1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: May 1993 + + 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. +*/ + +#include +#include +#include +#include +#include +#include +#include + +@implementation ReverseEnumerator + +- nextObject +{ + return [collection prevObjectWithEnumState: &enum_state]; +} + +@end + + +@implementation ConstantIndexedCollection + + +// GETTING MEMBERS BY INDEX; + +- objectAtIndex: (unsigned)index +{ + [self subclassResponsibility: _cmd]; + return nil; +} + +- firstObject +{ + if ([self isEmpty]) + return nil; + return [self objectAtIndex: 0]; +} + +- lastObject +{ + if ([self isEmpty]) + return nil; + return [self objectAtIndex: [self count]-1]; +} + + +// GETTING MEMBERS BY NEIGHBOR; + +/* Should be overriden by linked-list-type classes */ +- successorOfObject: anObject +{ + int last = [self count] - 1; + int index = [self indexOfObject: anObject]; + if (index == last) + return nil; + return [self objectAtIndex: index+1]; +} + +/* Should be overriden by linked-list-type classes */ +- predecessorOfObject: anObject +{ + int index = [self indexOfObject: anObject]; + if (index == 0) + return nil; + return [self objectAtIndex: index-1]; +} + + +// GETTING INDICES BY MEMBER; + +- (unsigned) indexOfObject: anObject +{ + int i, count = [self count]; + for (i = 0; i < count; i++) + if ([anObject isEqual: [self objectAtIndex:i]]) + return i; + return NO_INDEX; +} + +- (unsigned) indexOfObject: anObject inRange: (IndexRange)aRange +{ + int i; + + /* xxx check that aRange is within count */ + for (i = aRange.location; i < aRange.location+aRange.length; i++) + if ([anObject isEqual: [self objectAtIndex:i]]) + return i - aRange.location; + return NO_INDEX; +} + + +// TESTING; + +- (BOOL) contentsEqualInOrder: (id )aColl +{ + id o1, o2; + void *s1, *s2; + + if ([self count] != [aColl count]) + return NO; + s1 = [self newEnumState]; + s2 = [aColl newEnumState]; + while ((o1 = [self nextObjectWithEnumState:&s1]) + && (o2 = [aColl nextObjectWithEnumState:&s2])) + { + if (![o1 isEqual: o2]) + { + [self freeEnumState:&s1]; + [aColl freeEnumState:&s2]; + return NO; + } + } + [self freeEnumState:&s1]; + [aColl freeEnumState:&s2]; + return YES; +} + +- (int) compareInOrderContentsOf: (id )aCollection +{ + void *es1 = [self newEnumState]; + void *es2 = [aCollection newEnumState]; + id o1, o2; + int comparison; + while ((o1 = [self nextObjectWithEnumState:&es1]) + && (o2 = [aCollection nextObjectWithEnumState:&es2])) + { + if ((comparison = [o1 compare: o2])) + { + [self freeEnumState:&es1]; + [aCollection freeEnumState:&es2]; + return comparison; + } + } + if ((comparison = ([self count] - [aCollection count]))) + return comparison; + return 0; +} + +- (unsigned) indexOfFirstDifference: (id )aColl +{ + unsigned i = 0; + BOOL flag = YES; + void *enumState = [self newEnumState]; + id o1, o2; + FOR_INDEXED_COLLECTION_WHILE_TRUE(self, o1, flag) + { + if ((!(o2 = [self nextObjectWithEnumState: &enumState])) + || [o1 isEqual: o2]) + flag = NO; + else + i++; + } + END_FOR_INDEXED_COLLECTION_WHILE_TRUE(self); + [self freeEnumState: &enumState]; + return i; +} + +/* Could be more efficient */ +- (unsigned) indexOfFirstIn: (id )aCollection +{ + unsigned index = 0; + BOOL flag = YES; + id o; + + FOR_INDEXED_COLLECTION_WHILE_TRUE(self, o, flag) + { + if ([aCollection containsObject: o]) + flag = NO; + else + index++; + } + END_FOR_INDEXED_COLLECTION(self); + return index; +} + +/* Could be more efficient */ +- (unsigned) indexOfFirstNotIn: (id )aCollection +{ + unsigned index = 0; + BOOL flag = YES; + id o; + + FOR_INDEXED_COLLECTION_WHILE_TRUE(self, o, flag) + { + if (![aCollection containsObject: o]) + flag = NO; + else + index++; + } + END_FOR_INDEXED_COLLECTION(self); + return index; +} + + +// ENUMERATING; + +- (id ) reverseObjectEnumerator +{ + return [[[ReverseEnumerator alloc] initWithCollection: self] + autorelease]; +} + +- (void) withObjectsInRange: (IndexRange)aRange + invoke: (id )anInvocation +{ + int i; + for (i = aRange.location; i < aRange.location + aRange.length; i++) + [anInvocation invokeWithObject: [self objectAtIndex: i]]; +} + +- (void) withObjectsInReverseInvoke: (id )anInvocation +{ + int i, count = [self count]; + for (i = count-1; i >= 0; i--) + [anInvocation invokeWithObject: [self objectAtIndex: i]]; +} + +- (void) withObjectsInReverseInvoke: (id )anInvocation + whileTrue:(BOOL *)flag +{ + int i, count = [self count]; + for (i = count-1; *flag && i >= 0; i--) + [anInvocation invokeWithObject: [self objectAtIndex: i]]; +} + +- (void) makeObjectsPerformInReverse: (SEL)aSel +{ + id o; + FOR_INDEXED_COLLECTION_REVERSE(self, o) + { + [o performSelector: aSel]; + } + END_FOR_INDEXED_COLLECTION_REVERSE(self); +} + +- (void) makeObjectsPerformInReverse: (SEL)aSel withObject: argObject +{ + id o; + FOR_INDEXED_COLLECTION_REVERSE(self, o) + { + [o performSelector: aSel withObject: argObject]; + } + END_FOR_INDEXED_COLLECTION_REVERSE(self); +} + + + +// LOW-LEVEL ENUMERATING; + +- prevObjectWithEnumState: (void**)enumState +{ + /* *(int*)enumState is the index of the element that was returned + last time -prevObjectWithEnumState: or -nextObjectWithEnumState + was called. In -newEnumState, *(int*)enumState is initialized to + -2; The implementation of -newEnumState can be found below. */ + + /* If there are not objects in this collection, or we are being + asked for the object before the first object, return nil. */ + if ([self isEmpty] || ((*(int*)enumState) == 0) + || ((*(int*)enumState) == -1)) + { + (*(int*)enumState) = -1; + return NO_OBJECT; + } + + if (*(int*)enumState == -2) + /* enumState was just initialized by -newEnumState, start + at the end of the sequence. */ + *(int*)enumState = [self count]-1; + else + /* ...otherwise go the previous index. */ + (*(int*)enumState)--; + + return [self objectAtIndex:(*(unsigned*)enumState)]; +} + + + +// COPYING; + +- shallowCopyRange: (IndexRange)aRange +{ + [self notImplemented: _cmd]; + return nil; +} + +- shallowCopyInReverse +{ + [self notImplemented: _cmd]; + return nil; +} + +- shallowCopyInReverseRange: (IndexRange)aRange +{ + [self notImplemented: _cmd]; + return nil; +} + + +// OVERRIDE SOME COLLECTION METHODS; + +- (void*) newEnumState +{ + return (void*) -2; +} + +- nextObjectWithEnumState: (void**)enumState +{ + /* *(int*)enumState is the index of the element that was returned + last time -prevObjectWithEnumState: or -nextObjectWithEnumState + was called. In -newEnumState, *(int*)enumState is initialized to + -2. */ + + /* If there are not objects in this collection, or we are being + asked for the object after the last object, return nil. */ + if ([self isEmpty] || ((*(int*)enumState) >= (int)([self count]-1))) + { + (*(int*)enumState) = [self count]; + return NO_OBJECT; + } + + if (*(int*)enumState == -2) + /* enumState was just initialized by -newEnumState, start + at the beginning of the sequence. */ + *(int*)enumState = 0; + else + /* ...otherwise go the next index. */ + (*(int*)enumState)++; + + return [self objectAtIndex:(*(unsigned*)enumState)]; +} + +/* is this what we want? */ +- (BOOL) isEqual: anObject +{ + if (self == anObject) + return YES; + if ([anObject class] == [self class] + && [self count] != [anObject count] + && [self contentsEqualInOrder: anObject] ) + return YES; + else + return NO; +} + +@end + + + +@implementation IndexedCollection + ++ (void) initialize +{ + if (self == [IndexedCollection class]) + class_add_behavior(self, [Collection class]); +} + + +// REPLACING; + +- (void) replaceObjectAtIndex: (unsigned)index withObject: newObject +{ + [self subclassResponsibility: _cmd]; +} + + +// REMOVING; + +- (void) removeObjectAtIndex: (unsigned)index +{ + [self subclassResponsibility: _cmd]; +} + +- (void) removeFirstObject +{ + [self removeObjectAtIndex: 0]; +} + +- (void) removeLastObject +{ + [self removeObjectAtIndex: [self count]-1]; +} + +- (void) removeRange: (IndexRange)aRange +{ + int count = aRange.length; + + CHECK_INDEX_RANGE_ERROR(aRange.location, [self count]); + CHECK_INDEX_RANGE_ERROR(aRange.location+aRange.length-1, [self count]); + while (count--) + [self removeObjectAtIndex: aRange.location]; +} + + +// SORTING; + +- (void) sortContents +{ + [self notImplemented: _cmd]; +} + +- (void) sortAddObject: newObject +{ + [self notImplemented: _cmd]; +} + +// OVERRIDE SOME COLLECTION METHODS; + +- (void) removeObject: anObject +{ + unsigned index; + + /* Retain the object. Yuck, but necessary in case the array holds + the last reference to anObject. */ + /* xxx Is there an alternative to this expensive retain/release? */ + [anObject retain]; + + for (index = [self indexOfObject: anObject]; + index != NO_INDEX; + index = [self indexOfObject: anObject]) + [self removeObjectAtIndex: index]; + + [anObject release]; +} + +- (void) replaceObject: oldObject withObject: newObject +{ + unsigned index; + + /* Retain the object. Yuck, but necessary in case the array holds + the last reference to anObject. */ + /* xxx Is there an alternative to this expensive retain/release? */ + [oldObject retain]; + + for (index = [self indexOfObject: oldObject]; + index != NO_INDEX; + index = [self indexOfObject: oldObject]) + [self replaceObjectAtIndex: index withObject: newObject]; + + [oldObject release]; +} + +@end + + diff --git a/Old/IndexedCollectionPrivate.h b/Old/IndexedCollectionPrivate.h new file mode 100644 index 000000000..19fcd87f8 --- /dev/null +++ b/Old/IndexedCollectionPrivate.h @@ -0,0 +1,40 @@ +/* IndexedCollection definitions for the use of subclass implementations only + Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: May 1993 + + 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 __IndexedCollectionPrivate_h_GNUSTEP_BASE_INCLUDE +#define __IndexedCollectionPrivate_h_GNUSTEP_BASE_INCLUDE + +#include +#include +#include + +/* To be used inside a method for making sure that index + is not above range. +*/ +#define CHECK_INDEX_RANGE_ERROR(INDEX, OVER) \ +if (INDEX >= OVER) \ + [NSException raise: NSRangeException \ + format: @"in %s, index %d is out of range", \ + sel_get_name (_cmd), INDEX] + +#endif /* __IndexedCollectionPrivate_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/InvalidationListening.h b/Old/InvalidationListening.h new file mode 100644 index 000000000..70ded9d95 --- /dev/null +++ b/Old/InvalidationListening.h @@ -0,0 +1,38 @@ +/* Protocol for GNU Objective-C objects that understand an invalidation msg + Copyright (C) 1993,1994 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: July 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 __InvalidationListening_h_GNUSTEP_BASE_INCLUDE +#define __InvalidationListening_h_GNUSTEP_BASE_INCLUDE + +#include +/* This protocol is just temporary. It will disappear when GNU writes + a more general notification system. + It is not recommended that you use it in your code. */ + +@protocol InvalidationListening + +- senderIsInvalid: sender; + +@end + +#endif /* __InvalidationListening_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/Invocation.h b/Old/Invocation.h new file mode 100644 index 000000000..5eab6efbd --- /dev/null +++ b/Old/Invocation.h @@ -0,0 +1,98 @@ +#ifndef __Invocation_h_GNUSTEP_BASE_INCLUDE +#define __Invocation_h_GNUSTEP_BASE_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 +#include + +@interface Invocation : NSObject +{ + char *return_type; /* may actually contain full argframe type */ + unsigned return_size; + void *return_value; +} +- initWithReturnType: (const char *)encoding; +- (const char *) returnType; +- (unsigned) returnSize; +- (void) getReturnValue: (void*) addr; +@end + +@interface ArgframeInvocation : Invocation +{ + arglist_t argframe; + BOOL args_retained; + /* Use return_type to hold full argframe type. */ +} +- initWithArgframe: (arglist_t)frame type: (const char *)e; +- initWithType: (const char *)e; + +- (void) retainArguments; +- (BOOL) argumentsRetained; + +- (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 +{ + id *target_pointer; + SEL *sel_pointer; +} + +- initWithArgframe: (arglist_t)frame selector: (SEL)s; +- initWithSelector: (SEL)s; +- initWithTarget: target selector: (SEL)s, ...; +- (void) invokeWithTarget: t; +- (SEL) selector; +- (void) setSelector: (SEL)s; +- target; +- (void) setTarget: t; +@end + +/* Same as MethodInvocation, except that when sent + [ -invokeWithObject: anObj], anObj does not become the target + for the invocation's selector, it becomes the first object + argument of the selector. */ +@interface ObjectMethodInvocation : MethodInvocation +{ + id *arg_object_pointer; +} +@end + +@interface VoidFunctionInvocation : Invocation +{ + void (*function)(); +} +- initWithVoidFunction: (void(*)())f; +@end + + +@interface ObjectFunctionInvocation : Invocation +{ + id (*function)(id); +} +- initWithObjectFunction: (id(*)(id))f; +@end + + +#if 0 +@interface FunctionInvocation : ArgframeInvocation +{ + void (*function)(); +} +- initWithFunction: (void(*)())f + argframe: (arglist_t)frame type: (const char *)e; +- initWithFunction: (void(*)())f; +@end +#endif + +#endif /* __Invocation_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/Invocation.m b/Old/Invocation.m new file mode 100644 index 000000000..4c59a978f --- /dev/null +++ b/Old/Invocation.m @@ -0,0 +1,861 @@ +/* Implementation for Objective-C Invocation object + Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern BOOL sel_types_match(const char* t1, const char* t2); + +/* xxx We are currently retaining the return value. + We shouldn't always do this. Make is an option. */ + +/* Deal with strrchr: */ +#if STDC_HEADERS || HAVE_STRING_H +#include +/* An ANSI string.h and pre-ANSI memory.h might conflict. */ +#if !STDC_HEADERS && HAVE_MEMORY_H +#include +#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 +/* memory.h and strings.h conflict on some systems. */ +#endif /* not STDC_HEADERS and not HAVE_STRING_H */ + +/* xxx Perhaps make this an ivar. */ +#define return_retained 0 + +@implementation Invocation + +- initWithReturnType: (const char *)enc +{ + int l = strlen(enc); + OBJC_MALLOC(return_type, char, l + 1); + memcpy(return_type, enc, l); + return_type[l] = '\0'; + enc = objc_skip_type_qualifiers (return_type); + if (*enc != 'v') + { + /* Work around bug in objc_sizeof_type; it doesn't handle void type */ + return_size = objc_sizeof_type (enc); + return_value = objc_calloc (1, return_size); + } + else + { + return_size = 0; + return_value = NULL; + } + return self; +} + +- (void) encodeWithCoder: (id )coder +{ + [super encodeWithCoder: coder]; + [coder encodeValueOfCType: @encode(char*) + at: &return_type + withName: @"Invocation return type"]; + [coder encodeValueOfCType: @encode(unsigned) + at: &return_size + withName: @"Invocation return size"]; + if (return_size) + [coder encodeValueOfObjCType: return_type + at: return_value + withName: @"Invocation return value"]; +} + +- initWithCoder: (id )coder +{ + self = [super initWithCoder: coder]; + [coder decodeValueOfCType: @encode(char*) + at: &return_type + withName: NULL]; + [coder decodeValueOfCType: @encode(unsigned) + at: &return_size + withName: NULL]; + if (return_size) + { + return_value = objc_malloc (return_size); + [coder decodeValueOfObjCType: return_type + at: return_value + withName: NULL]; + } + else + return_value = 0; + return self; +} + +- (Class) classForConnectedCoder: coder +{ + /* Make sure that Connection's always send us bycopy, + i.e. as our own class, not a Proxy class. */ + return [self class]; +} + +/* Next two methods for OPENSTEP */ +- (Class) classForPortCoder +{ + return [self class]; +} +- replacementObjectForPortCoder: coder +{ + return self; +} + +- (void) invoke +{ + [self subclassResponsibility:_cmd]; +} + +- (void) invokeWithObject: anObj +{ + [self subclassResponsibility:_cmd]; +} + +- (const char *) returnType +{ + return return_type; +} + +- (unsigned) returnSize +{ + return return_size; +} + +- (void) getReturnValue: (void *)addr +{ + if (return_value) + memcpy (addr, return_value, return_size); + /* xxx what if it hasn't been invoked yet, and there isn't + a return value yet. */ +} + +- (void) setReturnValue: (void*)addr +{ + if (return_value) + { + if (return_retained && *return_type == _C_ID) + { + [*(id*)return_value release]; + *(id*)return_value = *(id*)addr; + [*(id*)return_value retain]; + } + else + memcpy (return_value, addr, return_size); + } +} + +- objectReturnValue +{ + switch (*return_type) + { +#define CASE_RETURN(C,T,S) \ + case C: return [NSNumber numberWith ## S: *(T*)return_value] + CASE_RETURN (_C_LNG, long, Long); + CASE_RETURN (_C_ULNG, unsigned long, UnsignedLong); + CASE_RETURN (_C_INT, int, Int); + CASE_RETURN (_C_UINT, unsigned int, UnsignedInt); + CASE_RETURN (_C_SHT, short, Short); + CASE_RETURN (_C_USHT, unsigned short, UnsignedShort); + CASE_RETURN (_C_CHR, char, Char); + CASE_RETURN (_C_UCHR, unsigned char, UnsignedChar); + CASE_RETURN (_C_FLT, float, Float); + CASE_RETURN (_C_DBL, double, Double); +#undef CASE_RETURN + case _C_PTR: + return [NSNumber numberWithUnsignedLong: (long) *(void**)return_value]; + case _C_CHARPTR: + return [NSString stringWithCString: *(char**)return_value]; + case _C_ID: + return *(id*)return_value; + case 'v': + return nil; + default: + [self notImplemented: _cmd]; + } + return 0; + [self notImplemented: _cmd]; + return nil; +} + +- (int) intReturnValue +{ + switch (*return_type) + { +#define CASE_RETURN(_C,_T) case _C: return (int) *(_T*)return_value + CASE_RETURN (_C_LNG, long); + CASE_RETURN (_C_ULNG, unsigned long); + CASE_RETURN (_C_INT, int); + CASE_RETURN (_C_UINT, unsigned int); + CASE_RETURN (_C_SHT, short); + CASE_RETURN (_C_USHT, unsigned short); + CASE_RETURN (_C_CHR, char); + CASE_RETURN (_C_UCHR, unsigned char); + CASE_RETURN (_C_CHARPTR, char*); + CASE_RETURN (_C_FLT, float); + CASE_RETURN (_C_DBL, double); + CASE_RETURN (_C_PTR, void*); +#undef CASE_RETURN + case _C_ID: + return [*(id*)return_value intValue]; + case 'v': + return 0; + default: + [self notImplemented: _cmd]; + } + return 0; +} + +- (BOOL) returnValueIsTrue +{ + switch (return_size) + { + case sizeof(char): + return (*(char*)return_value != 0); + case sizeof(short): + return (*(short*)return_value != 0); + case sizeof(int): + return (*(int*)return_value != 0); + } + { + int i; + for (i = 0; i < return_size; i++) + if (*((char*)return_value + i) != 0) + return YES; + return NO; + } +} + + +- (void) dealloc +{ + if (return_retained && *return_type == _C_ID) + [*(id*)return_value release]; + OBJC_FREE(return_type); + [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 + +- (void) _retainArguments +{ + const char *tmptype; + void *datum; + + tmptype = return_type; + while ((datum = my_method_get_next_argument (argframe, &tmptype))) + { + tmptype = objc_skip_type_qualifiers (tmptype); + if (*tmptype == _C_ID) + [*(id*)datum retain]; + } +} + +- (void) _initArgframeFrom: (arglist_t)frame + withType: (const char*)type + retainArgs: (BOOL)f +{ + int stack_argsize, reg_argsize; + + /* 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_calloc (1 ,sizeof(char*) + reg_argsize); + if (stack_argsize) + argframe->arg_ptr = objc_calloc (1, 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); + if (f) + { + [self _retainArguments]; + args_retained = YES; + } + } +} + +/* This is the designated initializer. */ +- initWithArgframe: (arglist_t)frame type: (const char *)type +{ + /* xxx we are just using the return part. Does this matter? */ + [super initWithReturnType: type]; + [self _initArgframeFrom: frame withType: type retainArgs: NO]; + + return self; +} + +- (void) encodeWithCoder: (id )coder +{ + const char *tmptype; + void *datum; + + [super encodeWithCoder: coder]; + tmptype = return_type; + while ((datum = my_method_get_next_argument(argframe, &tmptype))) + { + [coder encodeValueOfObjCType: tmptype + at: datum + withName: @"Invocation Argframe argument"]; + } +} + +- initWithCoder: (id )coder +{ + const char *tmptype; + void *datum; + + self = [super initWithCoder: coder]; + [self _initArgframeFrom: NULL withType: return_type retainArgs: NO]; + tmptype = return_type; + while ((datum = my_method_get_next_argument(argframe, &tmptype))) + { + [coder decodeValueOfObjCType: tmptype + at: datum + withName: NULL]; + } + return self; +} + +- initWithType: (const char *)e +{ + [self initWithArgframe:NULL type:e]; + return self; +} + +- (void) retainArguments +{ + if (!args_retained) + { + if (argframe) + [self _retainArguments]; + args_retained = YES; + } +} + +- (BOOL) argumentsRetained +{ + return args_retained; +} + +- (const char *) argumentTypeAtIndex: (unsigned)i +{ + const char *tmptype = return_type; + + do + { + tmptype = objc_skip_argspec (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 = return_type; + void *datum; + + do + datum = my_method_get_next_argument(argframe, &tmptype); + while (i-- && datum); + /* xxx Give error msg for null datum */ + memcpy (addr, datum, objc_sizeof_type(tmptype)); +} + +- (void) setArgument:(const void *)addr atIndex: (unsigned)i +{ + const char *tmptype = return_type; + void *datum; + + do + datum = my_method_get_next_argument(argframe, &tmptype); + while (i--); + memcpy (datum, addr, objc_sizeof_type(tmptype)); +} + +- (void) setArgumentAtIndex: (unsigned)i + toValueAt: (const void*)addr +{ + [self setArgument: addr atIndex: i]; +} + +- (void) _deallocArgframe +{ + if (argframe) + { + if (argframe->arg_ptr) + objc_free (argframe->arg_ptr); + objc_free (argframe); + } +} + +- (void) dealloc +{ + void *datum; + const char *tmptype = return_type; + while ((datum = my_method_get_next_argument(argframe, &tmptype))) + { + tmptype = objc_skip_type_qualifiers (tmptype); + if (args_retained && *tmptype == _C_ID) + [*(id*)datum release]; + } + [self _deallocArgframe]; + [super dealloc]; +} + +#if 0 +- resetArgframeWithReturnType: (const char*)encoding +{ + [self _deallocArgframe]; + [self _allocArgframe]; +} +#endif + +@end + +@implementation MethodInvocation + +- (void) _initTargetAndSelPointers +{ + const char *tmptype = return_type; + target_pointer = (id*) my_method_get_next_argument (argframe, &tmptype); + sel_pointer = (SEL*) my_method_get_next_argument (argframe, &tmptype); +} + +/* This is the designated initializer */ +- initWithArgframe: (arglist_t)frame type: (const char*)t +{ + [super initWithArgframe: frame type: t]; + [self _initTargetAndSelPointers]; + return self; +} + +- initWithArgframe: (arglist_t)frame selector: (SEL)sel +{ + const char *sel_type; + + if (! (sel_type = sel_get_type (sel)) ) + sel_type = sel_get_type ( sel_get_any_typed_uid (sel_get_name (sel))); + /* xxx Try harder to get this type by looking up the method in the target. + Hopefully the target can be found in the FRAME. */ + if (!sel_type) + [NSException raise: @"SelectorWithoutType" + format: @"Couldn't find encoding type for selector %s.", + sel_get_name (sel)]; + [self initWithArgframe: frame type: sel_type]; + if (!frame) + *sel_pointer = sel; + return self; +} + +- initWithCoder: (id )coder +{ + self = [super initWithCoder: coder]; + [self _initTargetAndSelPointers]; + return self; +} + +- initWithSelector: (SEL)s +{ + [self initWithArgframe: NULL selector: s]; + *sel_pointer = s; + return self; +} + +- initWithTarget: target selector: (SEL)s, ... +{ + const char *tmptype; + void *datum; + va_list ap; + + [self initWithArgframe: NULL selector: s]; + tmptype = return_type; + datum = my_method_get_next_argument(argframe, &tmptype); + if (args_retained) + [target retain]; + *((id*)datum) = target; + datum = my_method_get_next_argument(argframe, &tmptype); + *((SEL*)datum) = s; + datum = my_method_get_next_argument(argframe, &tmptype); + va_start (ap, s); + while (datum) + { + #define CASE_TYPE(_C,_T) case _C: *(_T*)datum = va_arg (ap, _T); break + switch (*tmptype) + { + case _C_ID: + *(id*)datum = va_arg (ap, id); + if (args_retained) + [*(id*)datum retain]; + break; + CASE_TYPE(_C_CLASS, Class); + CASE_TYPE(_C_SEL, SEL); + CASE_TYPE(_C_LNG, long); + CASE_TYPE(_C_ULNG, unsigned long); + CASE_TYPE(_C_INT, int); + CASE_TYPE(_C_UINT, unsigned int); + case _C_SHT: + *(short*)datum = (short)va_arg(ap, int); + break; + case _C_USHT: + *(unsigned short*)datum = (unsigned short)va_arg(ap, int); + break; + CASE_TYPE(_C_CHR, int); + case _C_UCHR: + *(unsigned char*)datum = (unsigned char)va_arg(ap, int); + break; + case _C_FLT: + *(float*)datum = (float)va_arg(ap, int); + break; + CASE_TYPE(_C_DBL, double); + CASE_TYPE(_C_CHARPTR, char*); + CASE_TYPE(_C_PTR, void*); + default: + { + int copysize; + copysize = objc_sizeof_type(tmptype); + memcpy(datum, (char *)va_arg(ap, int), copysize); + } /* default */ + } + datum = my_method_get_next_argument (argframe, &tmptype); + } + return self; +} + + +- (void) invoke +{ + void *ret; + IMP imp; + id target; + id cl; + SEL sel; + + /* xxx This could be more efficient by using my_method_get_next_argument + instead of -target and -selector. Or, even better, caching the + memory offsets of the target and selector in the argframe. */ + + target = *target_pointer; + if (target == nil) + return; + + cl = object_get_class (target); + sel = *sel_pointer; + /* xxx Perhaps we could speed things up by making this an ivar, + and caching it. */ + imp = get_imp (cl, sel); + NSAssert(imp, NSInternalInconsistencyException); + ret = __builtin_apply((void(*)(void))imp, + argframe, + types_get_size_of_stack_arguments(return_type)); + if (return_size) + { + if (*return_type == _C_ID) + { + id old = *(id*)return_value; + + mframe_decode_return(return_type, return_value, ret); + + if (return_retained && (*(id*)return_value != old)) + { + [old release]; + [*(id*)return_value retain]; + } + } + else + { + mframe_decode_return(return_type, return_value, ret); + } + } +} + +- (void) invokeWithTarget: t +{ + [self setTarget: t]; + [self invoke]; +} + +- (void) invokeWithObject: anObj +{ + [self invokeWithTarget: anObj]; +} + +- (SEL) selector +{ + return *sel_pointer; +} + +- (void) setSelector: (SEL)s +{ + SEL mysel = [self selector]; + if (mysel == (SEL)0) + /* XXX Type check is needed! (masata-y@is.aist-nara.ac.jp) */ + *sel_pointer = sel_get_any_typed_uid (sel_get_name (s)); + else if (sel_types_match(sel_get_type(mysel), sel_get_type(s))) + *sel_pointer = s; + else + { + /* We need to reallocate the argframe */ + [self notImplemented:_cmd]; + } +} + +- target +{ + return *target_pointer; +} + +- (void) setTarget: t +{ + if (*target_pointer != t) + { + if (args_retained) + { + [*target_pointer release]; + [t retain]; + } + *target_pointer = t; + } +} + +@end + +@implementation ObjectMethodInvocation + +- (void) _initArgObjectPointer +{ + const char *tmptype; + void *datum; + + tmptype = return_type; + my_method_get_next_argument (argframe, &tmptype); + my_method_get_next_argument (argframe, &tmptype); + do + { + datum = my_method_get_next_argument (argframe, &tmptype); + tmptype = objc_skip_type_qualifiers (tmptype); + } + while (datum && tmptype && *tmptype != _C_ID); + if (*tmptype != _C_ID) + [self error: "This method does not have an object argument."]; + arg_object_pointer = (id*) datum; +} + +- initWithArgframe: (arglist_t)frame selector: (SEL)sel +{ + [super initWithArgframe: frame selector: sel]; + [self _initArgObjectPointer]; + return self; +} + +- initWithCoder: (id )coder +{ + self = [super initWithCoder: coder]; + [self _initArgObjectPointer]; + return self; +} + +- (void) invokeWithObject: anObject +{ + if (*arg_object_pointer != anObject) + { + if (args_retained) + { + [*arg_object_pointer release]; + [anObject retain]; + } + *arg_object_pointer = anObject; + } + [self invoke]; +} + + +@end + +@implementation VoidFunctionInvocation + +#if 0 +- initWithFunction: (void(*)())f + argframe: (arglist_t)frame type: (const char *)e +{ + [super initWithArgframe: frame type: e]; + function = f; + return self; +} +#endif + +- initWithVoidFunction: (void(*)())f +{ + [super initWithReturnType: "v"]; + function = f; + return self; +} + +/* Encode ourself as a proxies across Connection's; we can't encode + a function across the wire. */ +- classForPortCoder +{ + return [NSDistantObject class]; +} + +- (void) encodeWithCoder: (id )coder +{ + [self shouldNotImplement: _cmd]; +} + +- (void) invoke +{ + (*function) (); +} + +- (void) invokeWithObject +{ + [self shouldNotImplement: _cmd]; +} + +@end + +@implementation ObjectFunctionInvocation + +- initWithObjectFunction: (id(*)(id))f +{ + [super initWithReturnType: "@"]; + function = f; + return self; +} + +/* Encode ourself as a proxies across Connection's; we can't encode + a function across the wire. */ +- classForPortCoder +{ + return [NSDistantObject class]; +} + +- (void) encodeWithCoder: (id )coder +{ + [self shouldNotImplement: _cmd]; +} + +- (void) invoke +{ + [self invokeWithObject: nil]; +} + +- (void) invokeWithObject: anObject +{ + id r; + + r = (*function) (anObject); + if (*(id*)return_value != r) + { + if (return_retained) + { + [*(id*)return_value release]; + [r retain]; + } + *(id*)return_value = r; + } +} + +@end + +/* Many other kinds of Invocations are possible: + SchemeInvocation, TclInvocation */ + +#if 0 +@implementation CurriedInvocation +@end + +What is this nonsense? +@interface StreamInvocation +@interface LogInvocation +@interface PrintingInvocation +{ + Stream *stream; + char *format_string; +} +@end +#endif diff --git a/Old/Invoking.h b/Old/Invoking.h new file mode 100644 index 000000000..e9b11ec65 --- /dev/null +++ b/Old/Invoking.h @@ -0,0 +1,42 @@ +/* Protocol for GNU Objective C invocations + Copyright (C) 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: February 1996 + + 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 __Invoking_h__GNUSTEP_BASE_INCLUDE +#define __Invoking_h__GNUSTEP_BASE_INCLUDE + +#include + +@protocol Invoking + +- (void) invoke; +- (void) invokeWithObject: anObject; + +- objectReturnValue; +- (int) intReturnValue; + +- (BOOL) returnValueIsTrue; + +@end + +#endif /* __Invoking_h__GNUSTEP_BASE_INCLUDE */ + diff --git a/Old/KeyedCollecting.h b/Old/KeyedCollecting.h new file mode 100644 index 000000000..c11823f7a --- /dev/null +++ b/Old/KeyedCollecting.h @@ -0,0 +1,81 @@ +/* Protocol for Objective-C objects holding (keyElement,contentElement) pairs. + Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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. +*/ + +/* The protocol inherits from the protocol. + + The protocol defines the interface to a + collection of elements that are accessible by a key, where the key is + some unique element. Pairs of (key element, content element) may be + added, removed and replaced. The keys and contents may be tested, + enumerated and copied. +*/ + +#ifndef __KeyedCollecting_h_GNUSTEP_BASE_INCLUDE +#define __KeyedCollecting_h_GNUSTEP_BASE_INCLUDE + +#include + +@protocol ConstantKeyedCollecting + +// INITIALIZING; +- initWithObjects: (id*)objects forKeys: (id*)keys count: (unsigned)c; + +// GETTING ELEMENTS AND KEYS; +- objectAtKey: aKey; +- keyOfObject: aContentObject; + +// TESTING; +- (BOOL) containsKey: aKey; + +// ENUMERATIONS; +- (id ) keyEnumerator; +- withKeyObjectsInvoke: (id )anInvocation; +- withKeyObjectsInvoke: (id )anInvocation + whileTrue: (BOOL *)flag; + +// LOW-LEVEL ENUMERATING; +- nextObjectAndKey: (id*)keyPtr withEnumState: (void**)enumState; + +// COPYING; +- shallowCopyValuesAs: (Class)aCollectingClass; +- shallowCopyKeysAs: (Class)aCollectingClass; +- copyValuesAs: (Class)aCollectingClass; +- copyKeysAs: (Class)aCollectingClass; + +@end + +@protocol KeyedCollecting + +// ADDING; +- (void) putObject: newContentObject atKey: aKey; + +// REPLACING AND SWAPPING; +- (void) replaceObjectAtKey: aKey with: newContentObject; +- (void) swapObjectsAtKeys: key1 : key2; + +// REMOVING; +- (void) removeObjectAtKey: aKey; + +@end + +#endif /* __KeyedCollecting_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/KeyedCollection.h b/Old/KeyedCollection.h new file mode 100644 index 000000000..e7e407547 --- /dev/null +++ b/Old/KeyedCollection.h @@ -0,0 +1,79 @@ +/* Interface for Objective-C KeyedCollection collection object + Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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 __KeyedCollection_h_GNUSTEP_BASE_INCLUDE +#define __KeyedCollection_h_GNUSTEP_BASE_INCLUDE + +#include +#include + +@interface ConstantKeyedCollection : Collection +@end + +@interface KeyedCollection : ConstantKeyedCollection +@end + +/* Put this on category instead of class to avoid bogus complaint from gcc */ +@interface ConstantKeyedCollection (Protocol) +@end +@interface KeyedCollection (Protocol) +@end + +@interface KeyEnumerator : Enumerator +@end + +#define FOR_KEYED_COLLECTION(ACOLL, ELT, KEY) \ +{ \ + void *_es = [ACOLL newEnumState]; \ + while ((ELT = [ACOLL nextObjectAndKey: &(KEY) withEnumState: &_es])) \ + { + +#define END_FOR_KEYED_COLLECTION(ACOLL) \ + } \ + [ACOLL freeEnumState: &_es]; \ +} + +#define FOR_KEYED_COLLECTION_WHILE_TRUE(ACOLL, ELT, KEY, FLAG) \ +{ \ + void *_es = [ACOLL newEnumState]; \ + while (FLAG && (ELT = [ACOLL nextObjectAndKey: &(KEY) \ + withEnumState: &_es])) \ + { + +#define END_FOR_KEYED_COLLECTION_WHILE_TRUE(ACOLL) \ + } \ + [ACOLL freeEnumState: &_es]; \ +} + + +/* The only subclassResponsibilities in IndexedCollection are: + + keyDescription + insertElement:atKey: + removeElementAtKey: + elementAtKey: + includesKey: + getNextKey:content:withEnumState: +*/ + +#endif /* __KeyedCollection_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/KeyedCollection.m b/Old/KeyedCollection.m new file mode 100644 index 000000000..30da7fbc4 --- /dev/null +++ b/Old/KeyedCollection.m @@ -0,0 +1,280 @@ +/* Implementation for Objective-C KeyedCollection collection object + Copyright (C) 1993,1994, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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. +*/ + +#include +#include +#include +#include +#include +#include +#include + +@implementation KeyEnumerator + +- nextObject +{ + id k; + [collection nextObjectAndKey: &k withEnumState: &enum_state]; + return k; +} + +@end + +@implementation ConstantKeyedCollection + + +// INITIALIZING; + +/* This is the designated initializer */ +- initWithObjects: (id*)objects forKeys: (id*)keys count: (unsigned)c +{ + [self subclassResponsibility: _cmd]; + return nil; +} + + +// GETTING ELEMENTS AND KEYS; + +- objectAtKey: aKey +{ + [self subclassResponsibility: _cmd]; + return nil; +} + +- keyOfObject: aContentObject +{ + [self subclassResponsibility: _cmd]; + return nil; +} + + +// TESTING; + +- (BOOL) containsKey: aKey +{ + if ([self objectAtKey: aKey] == NO_OBJECT) + return NO; + return YES; +} + + +// ENUMERATIONS; + +- (id ) keyEnumerator +{ + return [[[KeyEnumerator alloc] initWithCollection: self] + autorelease]; +} + +- (void) withKeysInvoke: (id )anInvocation +{ + id o, k; + + FOR_KEYED_COLLECTION(self, o, k) + { + [anInvocation invokeWithObject: k]; + } + END_FOR_KEYED_COLLECTION(self); +} + +- (void) withKeysInvoke: (id )anInvocation + whileTrue: (BOOL *)flag +{ + id o, k; + + FOR_KEYED_COLLECTION_WHILE_TRUE(self, o, k, *flag) + { + [anInvocation invokeWithObject: k]; + } + END_FOR_KEYED_COLLECTION(self); +} + +/* Override this Collection method */ +- nextObjectWithEnumState: (void**)enumState +{ + id k; + return [self nextObjectAndKey: &k withEnumState: enumState]; +} + + + +// LOW-LEVEL ENUMERATING; + +- nextObjectAndKey: (id*)keyPtr withEnumState: (void**)enumState +{ + [self subclassResponsibility: _cmd]; + return nil; +} + + + +// COPYING; + +- shallowCopyValuesAs: (Class)aConstantCollectingClass +{ + int count = [self count]; + id contents[count]; + id k; + int i = 0; + id o; + + FOR_KEYED_COLLECTION(self, o, k) + { + contents[i++] = o; + } + END_FOR_KEYED_COLLECTION(self); + return [[aConstantCollectingClass alloc] + initWithObjects: contents count: count]; +} + +- shallowCopyKeysAs: (Class)aCollectingClass; +{ + int count = [self count]; + id contents[count]; + id k; + int i = 0; + id o; + + FOR_KEYED_COLLECTION(self, o, k) + { + contents[i++] = k; + } + END_FOR_KEYED_COLLECTION(self); + return [[aCollectingClass alloc] + initWithObjects: contents count: count]; +} + +- copyValuesAs: (Class)aCollectingClass +{ + [self notImplemented: _cmd]; + return nil; +} + +- copyKeysAs: (Class)aCollectingClass; +{ + [self notImplemented: _cmd]; + return nil; +} + + +// ARCHIVING + +- (void) _encodeContentsWithCoder: (id )aCoder +{ + unsigned int count = [self count]; + id o, k; + + [aCoder encodeValueOfCType: @encode(unsigned) + at: &count + withName: @"Collection content count"]; + FOR_KEYED_COLLECTION(self, o, k) + { + [aCoder encodeObject: k + withName: @"KeyedCollection key"]; + [aCoder encodeObject: o + withName:@"KeyedCollection content"]; + } + END_FOR_KEYED_COLLECTION(self); +} + +- (void) _decodeContentsWithCoder: (id )aCoder +{ + unsigned int count, i; + id *objs, *keys; + + [aCoder decodeValueOfCType:@encode(unsigned) + at:&count + withName:NULL]; + OBJC_MALLOC(objs, id, count); + OBJC_MALLOC(keys, id, count); + for (i = 0; i < count; i++) + { + [aCoder decodeObjectAt: &(keys[i]) + withName: NULL]; + [aCoder decodeObjectAt: &(objs[i]) + withName: NULL]; + } + [self initWithObjects: objs forKeys: keys count: count]; + for (i = 0; i < count; i++) + { + [keys[i] release]; + [objs[i] release]; + } + OBJC_FREE(objs); + OBJC_FREE(keys); +} + +- (NSString*) description +{ + id s = [NSMutableString new]; + id o, k; + + FOR_KEYED_COLLECTION(self, o, k) + { + [s appendFormat: @"(%@,%@) ", [k description], [o description]]; + } + END_FOR_KEYED_COLLECTION(self); + [s appendFormat: @" :%s\n", object_get_class_name (self)]; + return [s autorelease]; +} + +@end + + + +@implementation KeyedCollection + ++ (void) initialize +{ + if (self == [KeyedCollection class]) + class_add_behavior(self, [Collection class]); +} + +// ADDING; +- (void) putObject: newContentObject atKey: aKey +{ + [self subclassResponsibility: _cmd]; +} + + +// REPLACING AND SWAPPING; + +- (void) replaceObjectAtKey: aKey with: newContentObject +{ + [self subclassResponsibility: _cmd]; +} + +- (void) swapObjectsAtKeys: key1 : key2 +{ + [self subclassResponsibility: _cmd]; +} + + +// REMOVING; +- (void) removeObjectAtKey: aKey +{ + [self subclassResponsibility: _cmd]; +} + +@end + diff --git a/Old/LinkedList.h b/Old/LinkedList.h new file mode 100644 index 000000000..0d57b8c2c --- /dev/null +++ b/Old/LinkedList.h @@ -0,0 +1,50 @@ +/* Interface for Objective-C LinkedList collection object + Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: May 1993 + + 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 __LinkedList_h_GNUSTEP_BASE_INCLUDE +#define __LinkedList_h_GNUSTEP_BASE_INCLUDE + +#include + +/* The protocol defines the interface to an object + that may be an element in a LinkedList. +*/ +@protocol LinkedListComprising +- nextLink; +- prevLink; +- (void) setNextLink: (id )aLink; +- (void) setPrevLink: (id )aLink; +- linkedList; +- (void) setLinkedList: aLinkedList; +@end + +@interface LinkedList : OrderedCollection +{ + id _first_link; + id _last_link; + unsigned int _count; +} + +@end + +#endif /* __LinkedList_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/LinkedList.m b/Old/LinkedList.m new file mode 100644 index 000000000..766724503 --- /dev/null +++ b/Old/LinkedList.m @@ -0,0 +1,408 @@ +/* Implementation for Objective-C LinkedList collection object + Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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. +*/ + +#include +#include +#include +#include + +@implementation LinkedList + +/* This is the designated initializer of this class */ +- init +{ + _count = 0; + _first_link = nil; + _last_link = nil; + return self; +} + +- initWithObjects: (id*)objs count: (unsigned)c +{ + [self init]; + while (c--) + [self prependObject: objs[c]]; + return self; +} + +/* Archiving must mimic the above designated initializer */ + +- (void) encodeWithCoder: coder +{ + id l; + + [super encodeWithCoder: coder]; + [coder encodeValueOfCType: @encode (typeof (_count)) + at: &_count + withName: @"LinkedList count"]; + FOR_COLLECTION (self, l) + { + [coder encodeObject: l + withName: @"LinkedList element"]; + } + END_FOR_COLLECTION (self); + [coder encodeObjectReference: _first_link + withName: @"LinkedList first link"]; + [coder encodeObjectReference: _last_link + withName: @"LinkedList last link"]; +} + +- initWithCoder: coder +{ + int i; + // id link; + + self = [super initWithCoder: coder]; + [coder decodeValueOfCType: @encode (typeof (_count)) + at: &_count + withName: NULL]; + /* We don't really care about storing the elements decoded, because + we access them through their own link pointers. */ + for (i = 0; i < _count; i++) + [coder decodeObjectAt: NULL + withName: NULL]; + [coder decodeObjectAt: &_first_link + withName: NULL]; + [coder decodeObjectAt: &_last_link + withName: NULL]; +#if 0 + /* xxx Not necessary, since the links encode this? + But should we rely on the links encoding this? + BUT! Look out: the next link pointers may not be set until + the last finishDecoding... method is run... */ + FOR_COLLECTION (self, link) + { + [link setLinkedList: self]; + } + END_FOR_COLLECTION (self); +#endif + return self; +} + +/* Empty copy must empty an allocCopy'ed version of self */ +- emptyCopy +{ + LinkedList *copy = [super emptyCopy]; + copy->_first_link = nil; + copy->_last_link = nil; + copy->_count = 0; + return copy; +} + +/* This must work without sending any messages to content objects */ +- (void) _empty +{ + _count = 0; + _first_link = nil; + _last_link = nil; +} + +/* These next four methods are the only ones that change the values of + the instance variables _count, _first_link, except for + "-init". */ + +- (void) removeObject: oldObject +{ + NSAssert([oldObject linkedList] == self, NSInternalInconsistencyException); + if (_first_link == oldObject) + { + if (_count > 1) + _first_link = [oldObject nextLink]; + else + _first_link = nil; + } + else + [[oldObject prevLink] setNextLink:[oldObject nextLink]]; + if (_last_link == oldObject) + { + if (_count > 1) + _last_link = [oldObject prevLink]; + else + _first_link = nil; + } + else + [[oldObject nextLink] setPrevLink:[oldObject prevLink]]; + _count--; + [oldObject setNextLink: NO_OBJECT]; + [oldObject setPrevLink: NO_OBJECT]; + [oldObject setLinkedList: NO_OBJECT]; + [oldObject release]; +} + +- (void) insertObject: newObject after: oldObject +{ + /* Make sure we actually own the oldObject. */ + NSAssert([oldObject linkedList] == self, NSInternalInconsistencyException); + + /* Make sure no one else already owns the newObject. */ + NSAssert([newObject linkedList] == NO_OBJECT, NSInternalInconsistencyException); + + /* Claim ownership of the newObject. */ + [newObject retain]; + [newObject setLinkedList: self]; + + /* Insert it. */ + if (_count == 0) + { + _first_link = newObject; + _last_link = newObject; + _count = 1; + [newObject setNextLink: NO_OBJECT]; + [newObject setPrevLink: NO_OBJECT]; + } + else + { + if (oldObject == _last_link) + _last_link = newObject; + [newObject setNextLink: [oldObject nextLink]]; + [newObject setPrevLink: oldObject]; + [[oldObject nextLink] setPrevLink: newObject]; + [oldObject setNextLink: newObject]; + } + _count++; +} + +- (void) insertObject: newObject before: oldObject +{ + /* Make sure we actually own the oldObject. */ + NSAssert([oldObject linkedList] == self, NSInternalInconsistencyException); + + /* Make sure no one else already owns the newObject. */ + NSAssert([newObject linkedList] == NO_OBJECT, NSInternalInconsistencyException); + + /* Claim ownership of the newObject. */ + [newObject retain]; + [newObject setLinkedList: self]; + + /* Insert it. */ + if (_count == 0) + { + _first_link = newObject; + _last_link = newObject; + _count = 1; + [newObject setNextLink: NO_OBJECT]; + [newObject setPrevLink: NO_OBJECT]; + } + else + { + if (oldObject == _first_link) + _first_link = newObject; + [newObject setPrevLink: [oldObject prevLink]]; + [newObject setNextLink: oldObject]; + [[oldObject prevLink] setNextLink: newObject]; + [oldObject setPrevLink: newObject]; + } + _count++; +} + +- (void) replaceObject: oldObject with: newObject +{ + /* Make sure we actually own the oldObject. */ + NSAssert([oldObject linkedList] == self, NSInternalInconsistencyException); + + /* Make sure no one else already owns the newObject. */ + NSAssert([newObject linkedList] == NO_OBJECT, NSInternalInconsistencyException); + + /* Claim ownership of the newObject. */ + [newObject retain]; + [newObject setLinkedList: self]; + + /* Do the replacement. */ + if (oldObject == _first_link) + _first_link = newObject; + [newObject setNextLink:[oldObject nextLink]]; + [newObject setPrevLink:[oldObject prevLink]]; + [[oldObject prevLink] setNextLink:newObject]; + [[oldObject nextLink] setPrevLink:newObject]; + + /* Release ownership of the oldObject. */ + [oldObject setNextLink: NO_OBJECT]; + [oldObject setPrevLink: NO_OBJECT]; + [oldObject setLinkedList: NO_OBJECT]; + [oldObject release]; +} + +/* End of methods that change the instance variables. */ + + +- (void) appendObject: newObject +{ + /* Make sure no one else already owns the newObject. */ + NSAssert([newObject linkedList] == NO_OBJECT, NSInternalInconsistencyException); + + /* Insert it. */ + if (_count == 0) + { + /* Claim ownership of the newObject. */ + [newObject retain]; + [newObject setLinkedList: self]; + + /* Put it in as the only node. */ + _first_link = newObject; + _last_link = newObject; + _count = 1; + [newObject setNextLink: NO_OBJECT]; + [newObject setPrevLink: NO_OBJECT]; + } + else + [self insertObject: newObject after: _last_link]; +} + +- (void) prependObject: newObject +{ + /* Make sure no one else already owns the newObject. */ + NSAssert([newObject linkedList] == NO_OBJECT, NSInternalInconsistencyException); + + /* Insert it. */ + if (_count == 0) + { + /* Claim ownership of the newObject. */ + [newObject retain]; + [newObject setLinkedList: self]; + + /* Put it in as the only node. */ + _first_link = newObject; + _last_link = newObject; + _count = 1; + [newObject setNextLink: NO_OBJECT]; + [newObject setPrevLink: NO_OBJECT]; + } + else + [self insertObject: newObject before: _first_link]; +} + +- (void) insertObject: newObject atIndex: (unsigned)index +{ + CHECK_INDEX_RANGE_ERROR(index, (_count+1)); + + /* Make sure no one else already owns the newObject. */ + NSAssert([newObject linkedList] == NO_OBJECT, NSInternalInconsistencyException); + + /* Insert it. */ + if (_count == 0) + { + /* Claim ownership of the newObject. */ + [newObject retain]; + [newObject setLinkedList: self]; + + /* Put it in as the only node. */ + _first_link = newObject; + _last_link = newObject; + _count = 1; + [newObject setNextLink: NO_OBJECT]; + [newObject setPrevLink: NO_OBJECT]; + } + else if (index == _count) + [self insertObject: newObject after: _last_link]; + else + [self insertObject:newObject before: [self objectAtIndex: index]]; +} + +- (void) removeObjectAtIndex: (unsigned)index +{ + CHECK_INDEX_RANGE_ERROR(index, _count); + [self removeObject: [self objectAtIndex: index]]; +} + +- objectAtIndex: (unsigned)index +{ + id link; + + CHECK_INDEX_RANGE_ERROR(index, _count); + + if (index < _count / 2) + for (link = _first_link; + index; + link = [link nextLink], index--) + ; + else + for (link = _last_link, index = _count - index - 1; + index; + link = [link prevLink], index--) + ; + return link; +} + +- firstObject +{ + return _first_link; +} + +- lastObject +{ + return _last_link; +} + +- successorOfObject: oldObject +{ + /* Make sure we actually own the oldObject. */ + NSAssert([oldObject linkedList] == self, NSInternalInconsistencyException); + + return [oldObject nextLink]; +} + +- predecessorOfObject: oldObject +{ + /* Make sure we actually own the oldObject. */ + NSAssert([oldObject linkedList] == self, NSInternalInconsistencyException); + + return [oldObject prevLink]; +} + +- (void*) newEnumState +{ + return _first_link; +} + +- nextObjectWithEnumState: (void**)enumState +{ + id ret; + + if (!*enumState) + return nil; + ret = *enumState; + *enumState = [(id)(*enumState) nextLink]; + /* *enumState points to the next object to be returned. */ + return ret; +} + +- prevObjectWithEnumState: (void**)enumState +{ + /* *enumState points to the object returned last time. */ + if (!*enumState) + return nil; + if (*enumState == _first_link) + /* enumState was just initialized from -newEnumState. */ + return *enumState = _last_link; + return (id) *enumState = [(id)(*enumState) prevLink]; +} + +- (unsigned) count +{ + return _count; +} + +@end + + + diff --git a/Old/LinkedListNode.h b/Old/LinkedListNode.h new file mode 100644 index 000000000..55342d9f6 --- /dev/null +++ b/Old/LinkedListNode.h @@ -0,0 +1,38 @@ +/* Interface for Objective-C LinkedListNode object + Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: May 1993 + + 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 __LinkedListNode_h_GNUSTEP_BASE_INCLUDE +#define __LinkedListNode_h_GNUSTEP_BASE_INCLUDE + +#include +#include + +@interface LinkedListNode : NSObject +{ + id _next; + id _prev; + id _linked_list; +} +@end + +#endif /* __LinkedListNode_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/LinkedListNode.m b/Old/LinkedListNode.m new file mode 100644 index 000000000..aa1bd206f --- /dev/null +++ b/Old/LinkedListNode.m @@ -0,0 +1,84 @@ +/* Implementation for Objective-C LinkedListNode object + Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: May 1993 + + 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. +*/ + +#include +#include +#include + +@implementation LinkedListNode + +- init +{ + [super init]; + _next = _prev = _linked_list = nil; + return self; +} + +- (void) encodeWithCoder: aCoder +{ + [super encodeWithCoder:aCoder]; + [aCoder encodeObjectReference:_next withName:@"Next LinkedList Node"]; + [aCoder encodeObjectReference:_prev withName:@"Prev LinkedList Node"]; + [aCoder encodeObjectReference:_linked_list withName:@"LinkedList"]; +} + +- initWithCoder: aCoder +{ + [super initWithCoder:aCoder]; + [aCoder decodeObjectAt:&_next withName:NULL]; + [aCoder decodeObjectAt:&_prev withName:NULL]; + [aCoder decodeObjectAt:&_linked_list withName:NULL]; + return self; +} + +- (id ) nextLink +{ + return _next; +} + +- (id ) prevLink +{ + return _prev; +} + +- (void) setNextLink: (id )aLink +{ + _next = aLink; +} + +- (void) setPrevLink: (id )aLink +{ + _prev = aLink; +} + +- linkedList +{ + return _linked_list; +} + +- (void) setLinkedList: anObject; +{ + _linked_list = anObject; +} + +@end diff --git a/Old/Locking.h b/Old/Locking.h new file mode 100644 index 000000000..997045d1a --- /dev/null +++ b/Old/Locking.h @@ -0,0 +1,34 @@ +/* Protocol for GNU Objective-C mutex locks + Copyright (C) 1993,1994 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: July 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 __Locking_h_GNUSTEP_BASE_INCLUDE +#define __Locking_h_GNUSTEP_BASE_INCLUDE + +#include + +@protocol Locking +- (void) lock; +- (void) unlock; +@end + +#endif /* __Locking_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/MachPort.h b/Old/MachPort.h new file mode 100644 index 000000000..a1384a76b --- /dev/null +++ b/Old/MachPort.h @@ -0,0 +1,39 @@ +/* Interface for Mach-port based object for use with Connection + Copyright (C) 1994, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: July 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 __MachPort_h_GNUSTEP_BASE_INCLUDE +#define __MachPort_h_GNUSTEP_BASE_INCLUDE + +#if __mach__ + +#include + +@interface MachInPort : InPort +@end + +@interface MachOutPort : OutPort +@end + +#endif /* __mach__ */ + +#endif /* __MachPort_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/MachPort.m b/Old/MachPort.m new file mode 100644 index 000000000..25d256c4f --- /dev/null +++ b/Old/MachPort.m @@ -0,0 +1,196 @@ +/* Implementation of Machport-based port object for use with Connection + Copyright (C) 1994, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: September 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. + */ + +/* This old code really needs work; it does not currently compile. */ + +#if __mach__ + +#include +#include +#include +#include +#include + +#include +#include + +static Dictionary *portDictionary; +static NSLock *portDictionaryGate; + +@implementation MachPort + ++ initialize +{ + portDictionaryGate = [NSLock new]; + NSAssert(sizeof(int) == sizeof(port_t), NSInternalInconsistencyException); + portDictionary = [[Dictionary alloc] + initWithType:@encode(id) + keyType:@encode(int)]; + return self; +} + +/* This not tested */ +static int +listen_for_invalidation (any_t arg) +{ + kern_return_t r; + notification_t m; + m.notify_header.msg_size = sizeof(notification_t); + m.notify_header.msg_local_port = task_notify(); + for (;;) + { + r = msg_receive((msg_header_t*)&m, MSG_OPTION_NONE, 0); + switch (r) + { + case RCV_SUCCESS: + fprintf(stderr, "notification id %d\n", (int)m.notify_header.msg_id); + break; + case RCV_TIMED_OUT: + fprintf(stderr, "notification msg_receive timed out\n"); + exit(-1); + default: + mach_error("notification", r); + exit(-1); + } + switch (m.notify_header.msg_id) + { + case NOTIFY_PORT_DELETED: + [[MachPort newFromMachPort:m.notify_port] invalidate]; + break; + case NOTIFY_MSG_ACCEPTED: + break; + case NOTIFY_PORT_DESTROYED: + [[MachPort newFromMachPort:m.notify_port] invalidate]; + break; + default: + mach_error("notification", r); + exit(-1); + } + /* Where do we free the object? */ + } + return 0; +} + +/* This not tested */ ++ listenForPortInvalidation +{ + MachPort *listenPort = [MachPort new]; + task_set_special_port(task_self(), TASK_NOTIFY_PORT, [listenPort mach_port]); + cthread_detach(cthread_fork((any_t)listen_for_invalidation, (any_t)0)); + return self; +} + +/* designated initializer */ ++ newFromMachPort: (port_t)p dealloc: (BOOL)f +{ + MachPort *aPort; + [portDictionaryGate lock]; + if ((aPort = [portDictionary elementAtKey:(int)p])) + { + [portDictionaryGate unlock]; + [aPort addReference]; + return aPort; + } + aPort = [[self alloc] init]; + aPort->mach_port = p; + aPort->deallocate = f; + [portDictionary addElement:aPort atKey:(int)p]; + [portDictionaryGate unlock]; + return aPort; +} + ++ newFromMachPort: (port_t)p +{ + return [self newFromMachPort:p dealloc:NO]; +} + ++ new +{ + kern_return_t error; + port_t p; + + if ((error=port_allocate(task_self(), &p)) != KERN_SUCCESS) { + mach_error("port_allocate failed", error); + exit(1); + } + return [self newFromMachPort:p]; +} + +- (void) encodeWithCoder: aCoder +{ + [aCoder encodeValueOfCType: @encode(BOOL) + at: &deallocate + withName: @""]; + [aCoder encodeMachPort: mach_port]; +} + ++ newWithCoder: aCoder +{ + BOOL f; + port_t mp; + MachPort *p; + + [aCoder decodeValueOfCType: @encode(BOOL) + at: &f + withName: NULL]; + [aCoder decodeMachPort: &mp]; + + p = [MachPort newFromMachPort:mp dealloc:f]; + return p; +} + +- (unsigned) hash +{ + /* What should this be? */ + return (unsigned)self; +} + +- (void) dealloc +{ + if (refcount-1 == 0) + { + [portDictionaryGate lock]; + [portDictionaryGate removeElementAtKey:(int)machPort]; + [portDictionaryGate unlock]; + if (deallocate) + { + kern_return_t error; + error = port_deallocate(task_self(), machPort); + if (error != KERN_SUCCESS) { + mach_error("port_deallocate failed", error); + exit(1); + } + } + } + [super dealloc]; + return self; +} + +- (mach_port_t) machPort +{ + return mach_port; +} + +@end + +#endif /* __mach__ */ diff --git a/Old/Magnitude.h b/Old/Magnitude.h new file mode 100644 index 000000000..fc458982d --- /dev/null +++ b/Old/Magnitude.h @@ -0,0 +1,33 @@ +/* Interface for Objective-C Magnitude object + Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: May 1993 + + 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 __Magnitude_h_GNUSTEP_BASE_INCLUDE +#define __Magnitude_h_GNUSTEP_BASE_INCLUDE + +#include + +@interface Magnitude : NSObject + +@end + +#endif /* __Magnitude_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/Magnitude.m b/Old/Magnitude.m new file mode 100644 index 000000000..b6290e845 --- /dev/null +++ b/Old/Magnitude.m @@ -0,0 +1,99 @@ +/* Implementation for Objective-C Magnitude object + Copyright (C) 1993,1994 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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. +*/ + +#include +#include +#include + +/* These methods accesses no instance variables. It is exactly the kind + of thing that should be a "behavior" associated with a protocol. + i.e. #3 on Steve Naroff's wish list. */ + +@implementation Magnitude + +- (int) compare: anObject +{ + return [super compare:anObject]; +} + +- (BOOL) greaterThan: anObject +{ + if ([self compare:anObject] > 0) + return YES; + else + return NO; +} + +- (BOOL) greaterThanOrEqual: anObject +{ + if ([self compare:anObject] >= 0) + return YES; + else + return NO; +} + + +- (BOOL) lessThan: anObject +{ + if ([self compare:anObject] < 0) + return YES; + else + return NO; +} + +- (BOOL) lessThanOrEqual: anObject +{ + if ([self compare:anObject] <= 0) + return YES; + else + return NO; +} + + +- (BOOL) between: firstObject and: secondObject +{ + if ([self compare:firstObject] >= 0 + && [self compare:secondObject] <= 0) + return YES; + else + return NO; +} + + +- maximum: anObject +{ + if ([self compare:anObject] >= 0) + return self; + else + return anObject; +} + +- minimum: anObject +{ + if ([self compare:anObject] <= 0) + return self; + else + return anObject; +} + +@end diff --git a/Old/MappedCollector.h b/Old/MappedCollector.h new file mode 100644 index 000000000..8c8453deb --- /dev/null +++ b/Old/MappedCollector.h @@ -0,0 +1,40 @@ +/* Interface for Objective-C MappedCollector collection object + Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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 __MappedCollector_h_GNUSTEP_BASE_INCLUDE +#define __MappedCollector_h_GNUSTEP_BASE_INCLUDE + +#include + +@interface MappedCollector : KeyedCollection +{ + id _map; + id _domain; +} + +- initWithCollection: (id )aDomain + map: (id )aMap; + +@end + +#endif /* __MappedCollector_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/MappedCollector.m b/Old/MappedCollector.m new file mode 100644 index 000000000..a00ce9117 --- /dev/null +++ b/Old/MappedCollector.m @@ -0,0 +1,138 @@ +/* Implementation for Objective-C MappedCollector collection object + Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: May 1993 + + 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. +*/ + +#include +#include +#include +#include + +@implementation MappedCollector + +/* This is the designated initializer for this class */ +- initWithCollection: (id )aDomain + map: (id )aMap +{ + _map = aMap; + _domain = aDomain; + return self; +} + +/* Archiving must mimic the above designated initializer */ + +- (void) encodeWithCoder: anEncoder +{ + [self notImplemented:_cmd]; +} + ++ newWithCoder: aDecoder +{ + [self notImplemented:_cmd]; + return self; +} + +/* Override our superclass' designated initializer */ +- initWithObjects: (id*)objects forKeys: (id*)keys count: (unsigned)c +{ + [self notImplemented: _cmd]; + return nil; +} + +/* Empty copy must empty an allocCopy'ed version of self */ +- emptyCopy +{ + MappedCollector *copy = [super emptyCopy]; + copy->_map = [_map emptyCopy]; + copy->_domain = [_domain emptyCopy]; + return copy; +} + +/* This must work without sending any messages to content objects */ +- (void) empty +{ + [_domain empty]; +} + +- objectAtKey: aKey +{ + return [_domain objectAtKey: [_map objectAtKey: aKey]]; +} + +- keyOfObject: aContentObject +{ + [self notImplemented: _cmd]; + return self; +} + +- (void) replaceObjectAtKey: aKey with: newObject +{ + return [_domain replaceObjectAtKey: [_map objectAtKey: aKey] + with: newObject]; +} + +- (void) putObject: newObject atKey: aKey +{ + return [_domain putObject: newObject + atKey: [_map objectAtKey:aKey]]; +} + +- (void) removeObjectAtKey: aKey +{ + return [_domain removeObjectAtKey: [_map objectAtKey: aKey]]; +} + +- (BOOL) containsKey: aKey +{ + return [_domain containsKey: [_map objectAtKey:aKey]]; +} + +- (void*) newEnumState +{ + return [_domain newEnumState]; +} + +- (void) freeEnumState: (void**)enumState +{ + return [_domain freeEnumState: enumState]; +} + +- nextObjectAndKey: (id*)keyPtr withEnumState: (void**)enumState +{ + id mapContent; + id domainKey; + + /* xxx This needs debugging; see checks/test02.m */ + while ((mapContent = [_map nextObjectAndKey:keyPtr withEnumState:enumState]) + && + (![_domain containsKey: (domainKey = [_map objectAtKey:*keyPtr])])) + ; + if (mapContent == NO_OBJECT) + return NO_OBJECT; + return [_domain objectAtKey: domainKey]; +} + +- species +{ + return [Dictionary class]; +} + +@end diff --git a/Old/MemoryStream.h b/Old/MemoryStream.h new file mode 100644 index 000000000..0427e9917 --- /dev/null +++ b/Old/MemoryStream.h @@ -0,0 +1,90 @@ +/* Interface for GNU Objective C memory stream + Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: July 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. + */ + +/* + Modified by: Richard Frith-Macdonald + Date: September 1997 + + Modifications to use NSData and NSMutable data objects to hold data. +*/ + +#ifndef __MemoryStream_h_GNUSTEP_BASE_INCLUDE +#define __MemoryStream_h_GNUSTEP_BASE_INCLUDE + +#include +#include + +/* This protocol is preliminary and may change. + This also may get pulled out into a separate .h file. */ + +@protocol MemoryStreaming + +- initWithCapacity: (unsigned)capacity; + +- (void) setStreamBufferCapacity: (unsigned)s; + +- (char*) streamBuffer; +- (unsigned) streamBufferCapacity; +- (unsigned) streamEofPosition; + +@end + +@interface MemoryStream : Stream +{ + id data; + int prefix; + int position; + int eof_position; + BOOL isMutable; +} + ++ (MemoryStream*)streamWithData: (id)anObject; + +- initWithCapacity: (unsigned)capacity + prefix: (unsigned)prefix; +- initWithData: (id)anObject; + +#if 0 +- initWithSize: (unsigned)s; /* For backwards compatibility, depricated */ +#endif + +- (id) data; +- (id) mutableData; +- (unsigned) streamBufferPrefix; +- (unsigned) streamBufferLength; /* prefix + eofPosition */ + +/* xxx This interface will change */ +- _initOnMallocBuffer: (char*)b + size: (unsigned)s /* size of malloc'ed buffer */ + eofPosition: (unsigned)l /* length of buffer with data for reading */ + prefix: (unsigned)p /* reset for this position */ + position: (unsigned)i; /* current position for reading/writing */ +- _initOnMallocBuffer: (char*)b + freeWhenDone: (BOOL)f + size: (unsigned)s /* size of malloc'ed buffer */ + eofPosition: (unsigned)l /* length of buffer with data for reading */ + prefix: (unsigned)p /* reset for this position */ + position: (unsigned)i; /* current position for reading/writing */ +@end + +#endif /* __MemoryStream_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/MemoryStream.m b/Old/MemoryStream.m new file mode 100644 index 000000000..e5367193a --- /dev/null +++ b/Old/MemoryStream.m @@ -0,0 +1,435 @@ +/* Implementation of GNU Objective C memory stream + Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: July 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Deal with memchr: */ +#if STDC_HEADERS || HAVE_STRING_H +#include +/* An ANSI string.h and pre-ANSI memory.h might conflict. */ +#if !STDC_HEADERS && HAVE_MEMORY_H +#include +#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 +/* memory.h and strings.h conflict on some systems. */ +#endif /* not STDC_HEADERS and not HAVE_STRING_H */ + +#define DEFAULT_MEMORY_STREAM_SIZE 64 + +extern int +o_vscanf (void *stream, + int (*inchar_func)(void*), + void (*unchar_func)(void*,int), + const char *format, va_list argptr); + +static BOOL debug_memory_stream = NO; + +/* A pretty stupid implementation based on realloc(), but it works for now. */ + +@implementation MemoryStream + ++ (MemoryStream*)streamWithData: (id)anObject +{ + return [[[MemoryStream alloc] initWithData:anObject] autorelease]; +} + +- (id) data +{ + return data; +} + +/* xxx This interface will change */ +- _initOnMallocBuffer: (char*)b + freeWhenDone: (BOOL)f + size: (unsigned)s /* size of malloc'ed buffer */ + eofPosition: (unsigned)l /* length of buffer with data for reading */ + prefix: (unsigned)p /* never read/write before this position */ + position: (unsigned)i /* current position for reading/writing */ +{ + self = [super init]; + if (self) + { + if (b) + if (f) + data = [[NSMutableData alloc] initWithBytesNoCopy: b length: s]; + else + data = [[NSMutableData alloc] initWithBytes: b length: s]; + else + { + data = [[NSMutableData alloc] initWithCapacity: s]; + if (data) + [data setLength: s]; + } + + if (data) + { + prefix = p; + position = i; + eof_position = l; + isMutable = YES; + if ([data length] < prefix + MAX(position, eof_position)) + [data setLength: prefix + MAX(position, eof_position)]; + } + else + { + [self release]; + self = nil; + } + } + return self; +} + +- _initOnMallocBuffer: (char*)b + size: (unsigned)s /* size of malloc'ed buffer */ + eofPosition: (unsigned)l /* length of buffer with data for reading */ + prefix: (unsigned)p /* never read/write before this position */ + position: (unsigned)i /* current position for reading/writing */ +{ + return [self _initOnMallocBuffer: b + freeWhenDone: YES + size: s + eofPosition: l + prefix: p + position: i]; +} + +/* xxx This method will disappear. */ +#if 0 +- initWithSize: (unsigned)s + prefix: (unsigned)p + position: (unsigned)i +{ + return [self _initOnMallocBuffer: 0 + freeWhenDone: YES + size: s + eofPosition: i + prefix: p + position: i]; +} +#endif + +- initWithCapacity: (unsigned)capacity + prefix: (unsigned)p +{ + return [self _initOnMallocBuffer: 0 + freeWhenDone: YES + size: capacity + eofPosition: 0 + prefix: p + position: 0]; +} + +- initWithCapacity: (unsigned)capacity +{ + return [self _initOnMallocBuffer: 0 + freeWhenDone: YES + size: capacity + eofPosition: 0 + prefix: 0 + position: 0]; +} + +- initWithData: (id)anObject +{ + self = [super init]; + if (self) + { + if (anObject && [anObject isKindOfClass:[NSData class]]) + { + data = [anObject retain]; + if ([data isKindOfClass:[NSMutableData class]]) + isMutable = YES; + eof_position = [data length]; + position = 0; + prefix = 0; + } + else + { + [self dealloc]; + self = nil; + } + } + return self; +} + +#if 0 +- initWithSize: (unsigned)s +{ + return [self initWithCapacity:s]; +} +#endif + +- init +{ + return [self initWithCapacity: DEFAULT_MEMORY_STREAM_SIZE]; +} + +- (BOOL) isWritable +{ + return isMutable; +} + +- (void) encodeWithCoder: anEncoder +{ + [self notImplemented:_cmd]; +} + ++ newWithCoder: aDecoder +{ + [self notImplemented:_cmd]; + return self; +} + +- (id) mutableData +{ + if (isMutable) + return data; + return nil; +} + +- (int) writeBytes: (const void*)b length: (int)l +{ + unsigned size; + + if (isMutable) + { + size = [data capacity]; + if (prefix+position+l > size) + { + size = MAX(prefix+position+l, size*2); + [data setCapacity: size]; + } + if (position+prefix+l > [data length]) + [data setLength: position+prefix+l]; + memcpy([data mutableBytes]+prefix+position, b, l); + position += l; + if (position > eof_position) + eof_position = position; + return l; + } + return 0; +} + +- (int) readBytes: (void*)b length: (int)l +{ + if (position+l > eof_position) + l = eof_position-position; + memcpy(b, [data bytes]+prefix+position, l); + position += l; + return l; +} + +- (NSString*) readLine +{ + char *nl = memchr([data bytes]+prefix+position, '\n', eof_position-position); + char *ret = NULL; + if (nl) + { + int len = nl-((char*)[data bytes])-prefix-position; + ret = objc_malloc (len+1); + strncpy(ret, ((char*)[data bytes])+prefix+position, len); + ret[len] = '\0'; + position += len+1; + } + return [[[NSString alloc] initWithCStringNoCopy: ret + length: strlen (ret) + freeWhenDone: YES] + autorelease]; +} + +/* Making these nested functions (which is what I'd like to do) is + crashing the va_arg stuff in vscanf(). Why? */ +#define MS ((MemoryStream*)s) + +int outchar_func(void *s, int c) +{ + if (MS->isMutable) + { + if (MS->prefix + MS->position >= [MS->data capacity]) + return EOF; + ((char*)[MS->data mutableBytes])[MS->prefix + MS->position++] = (char)c; + return 1; + } + return EOF; +} + +int inchar_func(void *s) +{ + if (MS->prefix + MS->position >= [MS->data length]) + return EOF; + return (int) ((char*)[MS->data bytes])[MS->prefix + MS->position++]; +} + +void unchar_func(void *s, int c) +{ + if (MS->position > 0) + MS->position--; + if (MS->isMutable) + ((char*)[MS->data mutableBytes])[MS->prefix + MS->position] = (char)c; +} + +#if HAVE_VSPRINTF +- (int) writeFormat: (NSString*)format + arguments: (va_list)arg +{ + unsigned size; + int ret; + + if (!isMutable) + return 0; + /* xxx Using this ugliness we at least let ourselves safely print + formatted strings up to 128 bytes long. + It's digusting, though, and we need to fix it. + Using GNU stdio streams would do the trick. + */ + size = [data capacity]; + if (size - (prefix + position) < 128) + size = MAX(size+128, size*2); + [data setLength: size]; + + ret = VSPRINTF_LENGTH (vsprintf([data mutableBytes]+prefix+position, + [format cString], arg)); + position += ret; + /* xxx Make sure we didn't overrun our buffer. + As per above kludge, this would happen if we happen to have more than + 128 bytes left in the buffer and we try to write a string longer than + the num bytes left in the buffer. */ + NSAssert(prefix + position <= [data capacity], @"buffer overrun"); + if (position > eof_position) + eof_position = position; + [data setLength:eof_position + prefix]; + if (debug_memory_stream) + { + *(char*)([data mutableBytes]+prefix+position) = '\0'; + fprintf(stderr, "%s\n", (char*)[data mutableBytes]+prefix); + } + return ret; +} +#endif + +- (int) readFormat: (NSString*)format, ... +{ + int ret; + va_list ap; + + va_start(ap, format); + ret = o_vscanf(self, inchar_func, unchar_func, + [format cString], ap); + va_end(ap); + return ret; +} + +- (void) setStreamPosition: (unsigned)i seekMode: (seek_mode_t)mode +{ + switch (mode) + { + case STREAM_SEEK_FROM_START: + position = i; + break; + case STREAM_SEEK_FROM_CURRENT: + position += i; + break; + case STREAM_SEEK_FROM_END: + position = eof_position + i; + break; + } +} + +- (unsigned) streamPosition +{ + return position; +} + +- (void) close +{ + [self flushStream]; +} + +- (void) dealloc +{ + [data release]; + [super dealloc]; +} + +- (BOOL) streamEof +{ + if (position == eof_position) + return YES; + else + return NO; +} + +- (unsigned) streamBufferCapacity +{ + if (isMutable) + return [data capacity]; + return [data length]; +} + +- (char*) streamBuffer +{ + if (isMutable) + return (char*)[data mutableBytes]; + return 0; +} + +- (void) setStreamBufferCapacity: (unsigned)s +{ + if (isMutable) + if (s > prefix + eof_position) + [data setCapacity:s]; +} + +- (unsigned) streamEofPosition +{ + return eof_position; +} + +- (void) setStreamEofPosition: (unsigned)i +{ + if (i < [data length] - prefix) + eof_position = i; +} + +- (unsigned) streamBufferPrefix +{ + return prefix; +} + +- (unsigned) streamBufferLength +{ + return prefix + eof_position; +} + +@end diff --git a/Old/NotificationDispatcher.h b/Old/NotificationDispatcher.h new file mode 100644 index 000000000..09b5f0b0d --- /dev/null +++ b/Old/NotificationDispatcher.h @@ -0,0 +1,221 @@ +/* Interface to object for broadcasting Notification objects + Copyright (C) 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: March 1996 + + 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 __NotificationDispatcher_h_GNUSTEP_BASE_INCLUDE +#define __NotificationDispatcher_h_GNUSTEP_BASE_INCLUDE + +/* A class for posting notifications to observer objects that request + them. + + This implementation has several advantages over OpenStep's + NSNotificationCenter: + + (1) Heavy use of hash tables and the use of LinkedList's make it + faster. Removing from the middle of LinkedList's is much more + efficient than removing from the middle of Array's. + + (2) The way in which notifications are dispatched can be specified as + invocation objects instead of just selectors. Invocation objects + are more flexible than selectors in that they can hold more context + and, if desired, can call C functions instead of sending a message + to an object; (this way you may be able to avoid creating a new + class just to handle certain notifications). + + (3) Instead of sending +defaultCenter, you can simply send +add..., + +remove... and +post... messages directly to the class object. + The class uses a static variable directly, instead of taking + the time for the extra +defaultCenter method call. It's both + easier for the user and more time efficient. + + (4) You can call -addObserver:... with both name and object being + nil. This request will receive postings of *all* notifications. + Wow. + + Although it offers extra features, the implementation has an + OpenStep-style interface also. + + */ + +#include +#include +#include +#include +#include + +@interface NotificationDispatcher : NSObject +{ + /* `nr' stands for Notification Request Object; the interface for + this class is defined in the .m file. One of these is created + for each -add... call. */ + + /* For those observer requests with NAME=nil and OBJECT=nil. */ + LinkedList *_anonymous_nr_list; + /* For those observer requests with NAME=nil and OBJECT!=nil. */ + NSMapTable *_object_2_nr_list; + /* For those observer requests with NAME!=nil, OBJECT may or may not =nil .*/ + NSMapTable *_name_2_nr_list; + + /* The keys are observers; the values are Array's containing all + NotificationInvocation objects associated with the observer key. */ + NSMapTable *_observer_2_nr_array; + + /* A mutex lock for making the ivars thread-safe. */ + NSRecursiveLock *_lock; +} + + +/* Adding new observers. */ + +/* Register INVOCATION to receive future notifictions that match NAME + and OBJECT. A nil passed as either NAME or OBJECT acts as a + wild-card. If NAME is nil, the NotificationDispatcher will send to + the observer all notification pertaining to OBJECT. If OBJECT is + nil, the NotificationDispatcher will send to the observer all + notification pertaining to NAME. If both OBJECT and NAME are nil, + send to the observer all notifications. + + The notification will be posted by sending -invokeWithObject: to + INVOCATION argument. The argument of -invokeWithObject: will be a + Notification object. This use of Invocation objects is more + flexible than using a selector, since Invocation's can be set up + with more arguments, hold more context, and can be C functions. + + OBJECT is not retained; this is done so these objects can tell when + there are no outstanding non-notification references remaining. If + an object may have added itself as an observer, it should call + +removeObserver: in its -dealloc method. + + INVOCATION and NAME, however, are retained. */ + +- (void) addInvocation: (id )invocation + name: (NSString*)name + object: object; + +/* Register OBSERVER to receive future notifications that match NAME + and OBJECT. A nil passed as either NAME or OBJECT acts as a + wild-card. If NAME is nil, the NotificationDispatcher will send to + the observer all notification pertaining to OBJECT. If OBJECT is + nil, the NotificationDispatcher will send to the observer all + notification pertaining to NAME. If both OBJECT and NAME are nil, + send to the observer all notifications. + + The notification will be posted by sending -perform:withObject: + to the observer, with SEL and a Notification object as arguments. + + Neither OBSERVER nor OBJECT are retained; this is done so these + objects can tell when there are no outstanding non-notification + references remaining. If an object may have added itself as an + observer, it should call +removeObserver: in its -dealloc method. + + INVOCATION and NAME, however, are retained. */ + +- (void) addObserver: observer + selector: (SEL)sel + name: (NSString*)name + object: object; + +/* Class versions of the above two methods that send these messages + to the default NotificationDispatcher for the class. */ + ++ (void) addInvocation: (id )invocation + name: (NSString*)name + object: object; ++ (void) addObserver: observer + selector: (SEL)sel + name: (NSString*)name + object: object; + + + +/* Removing observers. */ + +/* Remove all notification requests that would be sent to INVOCATION. */ + +- (void) removeInvocation: invocation; + +/* Remove the notification requests matching NAME and OBJECT that + would be sent to INVOCATION. As with adding an observation + request, nil NAME or OBJECT act as wildcards. */ + +- (void) removeInvocation: invocation + name: (NSString*)name + object: object; + +/* Remove all records pertaining to OBSERVER. For instance, this + should be called before the OBSERVER is -dealloc'ed. */ + +- (void) removeObserver: observer; + +/* Remove the notification requests for the given NAME and OBJECT + parameters. As with adding an observation request, nil NAME or + OBJECT act as wildcards. */ + +- (void) removeObserver: observer + name: (NSString*)name + object: object; + +/* Class versions of the above four methods that send these messages + to the default NotificationDispatcher for the class. */ + ++ (void) removeInvocation: invocation; ++ (void) removeInvocation: invocation + name: (NSString*)name + object: object; ++ (void) removeObserver: observer; ++ (void) removeObserver: observer + name: (NSString*)name + object: object; + + + +/* Post NOTIFICATION to all the observers that match its NAME and OBJECT. + The INFO arguent does not have to be a Dictionary. If there is a single + object that should be associated with the notification, you can simply + pass that single object instead of a Dictionary containing the object. */ + +- (void) postNotification: notification; +- (void) postNotificationName: (NSString*)name + object: object; +- (void) postNotificationName: (NSString*)name + object: object + userInfo: info; + +/* Class versions of the above three methods that send these messages + to the default NotificationDispatcher for the class. */ + ++ (void) postNotification: notification; ++ (void) postNotificationName: (NSString*)name + object: object; ++ (void) postNotificationName: (NSString*)name + object: object + userInfo: info; + ++ defaultInstance; + +@end + +@interface NotificationDispatcher (OpenStepCompat) ++ defaultCenter; +@end + +#endif /* __NotificationDispatcher_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/NotificationDispatcher.m b/Old/NotificationDispatcher.m new file mode 100644 index 000000000..6fd5d277b --- /dev/null +++ b/Old/NotificationDispatcher.m @@ -0,0 +1,750 @@ +/* Implementation of object for broadcasting Notification objects + Copyright (C) 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: March 1996 + + 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. +*/ + +/* The implementation for NotificationDispatcher. */ + +/* NeXT says you can only have one NotificationCenter per task; + I don't think GNU needs this restriction with its corresponding + NotificationDistributor class. */ + +#include +#include +#include +#include +#include +#include +#include + + +/* NotificationRequest class - One of these objects is created for + each -addObserver... request. It holds the requested invocation, + name and object. Each object is placed + (1) in one LinkedList, as keyed by the NAME/OBJECT parameters (accessible + through one of the ivars: anonymous_nr_list, object_2_nr_list, + name_2_nr_list), and + (2) in the Array, as keyed by the OBSERVER (as accessible through + the ivar observer_2_nr_array. + + To post a notification in satisfaction of this request, + send -postNotification:. */ + +@interface NotificationRequest : LinkedListNode +{ + int _retain_count; + id _name; + id _object; +} +- initWithName: n object: o; +- (NSString*) notificationName; +- notificationObject; +- (void) postNotification: n; +@end + +@implementation NotificationRequest + +- initWithName: n object: o +{ + [super init]; + _retain_count = 0; + _name = [n retain]; + _object = o; + /* Note that OBJECT is not retained. See the comment for + -addObserver... in NotificationDispatcher.h. */ + return self; +} + +/* Implement these retain/release methods here for efficiency, since + NotificationRequest's get retained and released by all their + holders. Doing this is a judgement call; I'm choosing speed over + space. */ + +- retain +{ + _retain_count++; + return self; +} + +- (oneway void) release +{ + if (_retain_count-- == 0) + [self dealloc]; +} + +- (unsigned) retainCount +{ + return _retain_count + 1; +} + +- (void) dealloc +{ + [_name release]; + [super dealloc]; +} + +- (BOOL)isEqual:other +{ + if ([self class] != [other class]) + return NO; + if (_object != [other notificationObject]) + return NO; + if (_name != [other notificationName] && + ![_name isEqual: [other notificationName]]) + return NO; + return YES; +} + +- (NSString*) notificationName +{ + return _name; +} + +- notificationObject +{ + return _object; +} + +- (void) postNotification: n +{ + [self subclassResponsibility: _cmd]; +} + +@end + + +@interface NotificationInvocation : NotificationRequest +{ + id _invocation; +} +- initWithInvocation: i name: n object: o; +@end + +@implementation NotificationInvocation + +- initWithInvocation: i name: n object: o +{ + [super initWithName: n object: o]; + _invocation = [i retain]; + return self; +} + +- (void) dealloc +{ + [_invocation release]; + [super dealloc]; +} + +- (void) postNotification: n +{ + [_invocation invokeWithObject: n]; +} + +@end + + +@interface NotificationPerformer : NotificationRequest +{ + id _target; + SEL _selector; +} +- initWithTarget: t selector: (SEL)s name: n object: o; +@end + +@implementation NotificationPerformer + +- initWithTarget: t selector: (SEL)s name: n object: o +{ + [super initWithName: n object: o]; + /* Note that TARGET is not retained. See the comment for + -addObserver... in NotificationDispatcher.h. */ + _target = t; + _selector = s; + return self; +} + +- (void) postNotification: n +{ + [_target performSelector: _selector withObject: n]; +} + +@end + + + + +@implementation NotificationDispatcher + +/* The default instance, most often the only one created. + It is accessed by the class methods at the end of this file. + There is no need to mutex locking of this variable. */ +static NotificationDispatcher *default_notification_dispatcher = nil; + ++ (void) initialize +{ + if (self == [NotificationDispatcher class]) + default_notification_dispatcher = [self new]; +} + + + +/* Initializing. */ + +- init +{ + [super init]; + _anonymous_nr_list = [LinkedList new]; + + /* Use NSNonOwnedPointerOrNullMapKeyCallBacks so we won't retain + the object. We will, however, retain the values, which are + LinkedList's. */ + _object_2_nr_list = + NSCreateMapTable (NSNonOwnedPointerOrNullMapKeyCallBacks, + NSObjectMapValueCallBacks, 0); + + /* Use NSObjectMapKeyCallBacks so we retain the NAME. We also retain + the values, which are LinkedList's. */ + _name_2_nr_list = + NSCreateMapTable (NSObjectMapKeyCallBacks, + NSObjectMapValueCallBacks, 0); + + /* Use NSNonOwnedPointerOrNullMapKeyCallBacks so we won't retain + the observer. We will, however, retain the values, which are Array's. */ + _observer_2_nr_array = + NSCreateMapTable (NSNonOwnedPointerOrNullMapKeyCallBacks, + NSObjectMapValueCallBacks, 0); + + _lock = [NSRecursiveLock new]; + + return self; +} + +- (void) dealloc +{ + [_anonymous_nr_list release]; + NSFreeMapTable( _object_2_nr_list); + NSFreeMapTable (_name_2_nr_list); + NSFreeMapTable (_observer_2_nr_array); + [_lock release]; + [super dealloc]; +} + + +/* Adding new observers. */ + +/* This is the (private) designated method for adding observers. If we + came from -addInvocation... then OBSERVER is actually an Invocation. */ + +- (void) _addObserver: observer + notificationRequest: nr + name: (NSString*)name + object: object +{ + /* If observer is nil, there is nothing to do; return. */ + if (!observer) + return; + + [_lock lock]; + + /* Record the notification request in an array keyed by OBSERVER. */ + { + /* Find the array of all the requests by OBSERVER. */ + Array *nr_array = NSMapGet (_observer_2_nr_array, observer); + if (!nr_array) + { + nr_array = [Array new]; + /* nr_array is retained; observer is not. */ + NSMapInsert (_observer_2_nr_array, observer, nr_array); + /* Now that nr_array is retained by the map table, release it; + this way the array will be completely released when the + map table is done with it. */ + [nr_array release]; + } + /* If the observer is already watching this request, do nothing. */ + if ([nr_array containsObject:nr]) + { + [_lock unlock]; + return; + } + [nr_array appendObject: nr]; + } + + /* Record the NotificationRequest in one of three MapTable->LinkedLists. */ + + /* Record the request in one, and only one, LinkedList. The LinkedList + is stored in a hash table accessed by a key. Which key is used + depends on what combination of NAME and OBJECT are non-nil. */ + if (!name) + { + if (!object) + { + /* This NotificationRequest will get posted notifications + for all NAME and OBJECT combinations. */ + [_anonymous_nr_list appendObject: nr]; + } + else + { + LinkedList *nr_list = NSMapGet (_object_2_nr_list, object); + if (!nr_list) + { + nr_list = [LinkedList new]; + /* nr_list is retained; object is not retained. */ + NSMapInsert (_object_2_nr_list, object, nr_list); + /* Now that nr_list is retained by the map table, release it; + this way the list will be completely released when the + map table is done with it. */ + [nr_list release]; + } + [nr_list appendObject: nr]; + } + } + else + { + LinkedList *nr_list = NSMapGet (_name_2_nr_list, name); + if (!nr_list) + { + nr_list = [LinkedList new]; + /* nr_list is retained; object is not retained. */ + NSMapInsert (_name_2_nr_list, name, nr_list); + /* Now that nr_list is retained by the map table, release it; + this way the list will be completely released when the + map table is done with it. */ + [nr_list release]; + } + [nr_list appendObject: nr]; + } + + [_lock unlock]; +} + +- (void) addInvocation: (id )invocation + name: (NSString*)name + object: object +{ + id nr; + + /* Create the NotificationRequest object that will hold this + observation request. This will retain INVOCATION and NAME. */ + nr = [[NotificationInvocation alloc] + initWithInvocation: invocation + name: name + object: object]; + + /* Record it in all the right places. */ + [self _addObserver: invocation + notificationRequest: nr + name: name + object: object]; + + /* Since nr was retained when it was added to the Array and + LinkedList above, we can release it now. */ + [nr release]; +} + + +/* For those that want to specify a selector instead of an invocation + as a way to contact the observer. */ + +- (void) addObserver: observer + selector: (SEL)sel + name: (NSString*)name + object: object +{ + id nr; + + /* Create the NotificationRequest object that will hold this + observation request. This will retain INVOCATION and NAME. */ + nr = [[NotificationPerformer alloc] + initWithTarget: observer + selector: sel + name: name + object: object]; + + /* Record it in all the right places. */ + [self _addObserver: observer + notificationRequest: nr + name: name + object: object]; + + /* Since nr was retained when it was added to the Array and + LinkedList above, we can release it now. */ + [nr release]; +} + + +/* Removing objects. */ + +/* A private method. + Remove the NR object from its one LinkedList; if this is the last + element of that LinkedList, and the LinkedList is map-accessible, + also release the LinkedList. */ + +- (void) _removeFromLinkedListNotificationRequest: nr +{ + id nr_list = [nr linkedList]; + + /* See if, instead of removing the NR from its LinkedList, we can + actually release the entire list. */ + if ([nr_list count] == 1 + && nr_list != _anonymous_nr_list) + { + id nr_name; + id nr_object; + LinkedList *mapped_nr_list; + + NSAssert([nr_list firstObject] == nr, NSInternalInconsistencyException); + if ((nr_name = [nr notificationName])) + { + mapped_nr_list = NSMapGet (_name_2_nr_list, nr_name); + NSAssert(mapped_nr_list == nr_list, NSInternalInconsistencyException); + NSMapRemove (_name_2_nr_list, nr_name); + } + else + { + nr_object = [nr notificationObject]; + NSAssert(nr_object, NSInternalInconsistencyException); + mapped_nr_list = NSMapGet (_object_2_nr_list, nr_object); + NSAssert(mapped_nr_list == nr_list, NSInternalInconsistencyException); + NSMapRemove (_object_2_nr_list, nr_object); + } + } + else + [nr_list removeObject: nr]; +} + + +/* Removing notification requests. */ + +/* Remove all notification requests that would be sent to INVOCATION. */ + +- (void) removeInvocation: invocation +{ + [self removeObserver: invocation]; +} + +/* Remove the notification requests matching NAME and OBJECT that + would be sent to INVOCATION. As with adding an observation + request, nil NAME or OBJECT act as wildcards. */ + +- (void) removeInvocation: invocation + name: (NSString*)name + object: object +{ + [self removeObserver: invocation + name: name + object: object]; +} + + + +/* Remove all records pertaining to OBSERVER. For instance, this + should be called before the OBSERVER is -dealloc'ed. */ + +- (void) removeObserver: observer +{ + Array *observer_nr_array; + NotificationRequest *nr; + + /* If OBSERVER is nil, do nothing; just return. NOTE: This *does not* + remove all requests with a nil OBSERVER; it would be too easy to + unintentionally remove other's requests that way. If you need to + remove a request with a nil OBSERVER, use -removeObserver:name:object: */ + if (!observer) + return; + + [_lock lock]; + + /* Get the array of NotificationRequest's associated with OBSERVER. */ + observer_nr_array = NSMapGet (_observer_2_nr_array, observer); + + if (!observer_nr_array) + /* OBSERVER was never registered for any notification requests with us. + Nothing to do. */ + return; + + /* Remove each of these from it's LinkedList. */ + FOR_ARRAY (observer_nr_array, nr) + { + [self _removeFromLinkedListNotificationRequest: nr]; + } + END_FOR_ARRAY (observer_nr_array); + + /* Remove from the MapTable the list of NotificationRequest's + associated with OBSERVER. This also releases the observer_nr_array, + and its contents. */ + NSMapRemove (_observer_2_nr_array, observer); + + [_lock unlock]; +} + + +/* Remove the notification requests for the given parameters. As with + adding an observation request, nil NAME or OBJECT act as wildcards. */ + +- (void) removeObserver: observer + name: (NSString*)name + object: object +{ + Array *observer_nr_array; + + /* If both NAME and OBJECT are nil, this call is the same as + -removeObserver:, so just call it. */ + if (!name && !object) + [self removeObserver: observer]; + + /* We are now guaranteed that at least one of NAME and OBJECT is non-nil. */ + + [_lock lock]; + + /* Get the list of NotificationRequest's associated with OBSERVER. */ + observer_nr_array = NSMapGet (_observer_2_nr_array, observer); + + if (!observer_nr_array) + /* OBSERVER was never registered for any notification requests with us. + Nothing to do. */ + return; + + /* Find those NotificationRequest's from the array that + match NAME and OBJECT, and remove them from the array and + their linked list. */ + /* xxx If we thought the LinkedList from the map table keyed on NAME + would be shorter, we could use that instead. */ + { + NotificationRequest *nr; + int count = [observer_nr_array count]; + int i; + + for (i = count-1; i >= 0; i--) + { + nr = [observer_nr_array objectAtIndex: i]; + if ((!name || [name isEqual: [nr notificationName]]) + && (!object || [object isEqual: [nr notificationObject]])) + { + /* We can remove from the array, even though we are "enumerating" + over it, because we are enumerating from back-to-front, + and the indices of yet-to-come objects don't change when + high-indexed objects are removed. */ + [observer_nr_array removeObjectAtIndex: i]; + [self _removeFromLinkedListNotificationRequest: nr]; + } + } + /* xxx If there are some LinkedList's that are empty, I should + remove them from the map table's. */ + } + + [_lock unlock]; +} + + +/* Post NOTIFICATION to all the observers that match its NAME and OBJECT. */ + +- (void) postNotification: notification +{ + id notification_name = [(NSNotification *)notification name]; + id notification_object = [notification object]; + id nr; + LinkedList *nr_list; + NSMutableArray* array; + + /* Make sure the notification has a name. */ + if (!notification_name) + [NSException raise: NSInvalidArgumentException + format: @"Tried to post a notification with no name."]; + + [_lock lock]; + + array = [[NSMutableArray arrayWithCapacity:10] retain]; + + /* Post the notification to all the observers that specified neither + NAME or OBJECT. */ + if ([_anonymous_nr_list count]) + { + FOR_COLLECTION (_anonymous_nr_list, nr) + { + [array addObject:nr]; + } + END_FOR_COLLECTION (_anonymous_nr_list); + while ([array count] > 0) + { + nr = [array objectAtIndex:0]; + + if ([nr linkedList] != NO_OBJECT) /* Has request been removed? */ + [nr postNotification:notification]; + [array removeObjectAtIndex:0]; + } + } + + /* Post the notification to all the observers that specified OBJECT, + but didn't specify NAME. */ + if (notification_object) + { + nr_list = NSMapGet (_object_2_nr_list, notification_object); + if (nr_list) + { + FOR_COLLECTION (nr_list, nr) + { + [array addObject:nr]; + } + END_FOR_COLLECTION (nr_list); + while ([array count] > 0) + { + nr = [array objectAtIndex:0]; + + if ([nr linkedList] != NO_OBJECT) /* Has request been removed? */ + [nr postNotification:notification]; + [array removeObjectAtIndex:0]; + } + } + } + + /* Post the notification to all the observers of NAME; (and if the + observer's OBJECT is non-nil, don't send unless the observer's OBJECT + matches the notification's OBJECT). */ + nr_list = NSMapGet (_name_2_nr_list, notification_name); + if (nr_list) + { + FOR_COLLECTION (nr_list, nr) + { + id nr_object = [nr notificationObject]; + if (!nr_object || nr_object == notification_object) + [array addObject:nr]; + } + END_FOR_COLLECTION (nr_list); + while ([array count] > 0) + { + nr = [array objectAtIndex:0]; + + if ([nr linkedList] != NO_OBJECT) /* Has request been removed? */ + [nr postNotification:notification]; + [array removeObjectAtIndex:0]; + } + } + + [array release]; + + [_lock unlock]; +} + +- (void) postNotificationName: (NSString*)name + object: object +{ + [self postNotification: [NSNotification notificationWithName: name + object: object]]; +} + +- (void) postNotificationName: (NSString*)name + object: object + userInfo: info +{ + [self postNotification: [NSNotification notificationWithName: name + object: object + userInfo: info]]; +} + + + +/* Class methods. */ + ++ defaultInstance +{ + return default_notification_dispatcher; +} + ++ (void) addInvocation: (id )invocation + name: (NSString*)name + object: object +{ + [default_notification_dispatcher addInvocation: invocation + name: name + object: object]; +} + ++ (void) addObserver: observer + selector: (SEL)sel + name: (NSString*)name + object: object +{ + [default_notification_dispatcher addObserver: observer + selector: sel + name: name + object: object]; +} + ++ (void) removeInvocation: invocation +{ + [default_notification_dispatcher removeInvocation: invocation]; +} + ++ (void) removeInvocation: invocation + name: (NSString*)name + object: object +{ + [default_notification_dispatcher removeInvocation: invocation + name: name + object: object]; +} + ++ (void) removeObserver: observer +{ + [default_notification_dispatcher removeObserver: observer]; +} + ++ (void) removeObserver: observer + name: (NSString*)name + object: object +{ + [default_notification_dispatcher removeObserver: observer + name: name + object: object]; +} + ++ (void) postNotification: notification +{ + [default_notification_dispatcher postNotification: notification]; +} + ++ (void) postNotificationName: (NSString*)name + object: object +{ + [default_notification_dispatcher postNotificationName: name + object: object]; +} + ++ (void) postNotificationName: (NSString*)name + object: object + userInfo: info +{ + [default_notification_dispatcher postNotificationName: name + object: object + userInfo: info]; +} + +@end + +@implementation NotificationDispatcher (OpenStepCompat) + +/* For OpenStep compatibility. */ ++ defaultCenter +{ + return default_notification_dispatcher; +} + +@end diff --git a/Old/OldNSConnection.h b/Old/OldNSConnection.h new file mode 100644 index 000000000..1a946f9b9 --- /dev/null +++ b/Old/OldNSConnection.h @@ -0,0 +1,558 @@ +#if NEW_DO +/* Interface for GNU Objective-C version of NSConnection + Copyright (C) 1997,2000 Free Software Foundation, Inc. + + Original by: Andrew Kachites McCallum + Version for OPENSTEP by: Richard Frith-Macdonald + Created: August 1997, updated June 2000 + + 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 __NSConnection_h_GNUSTEP_BASE_INCLUDE +#define __NSConnection_h_GNUSTEP_BASE_INCLUDE + +#include +#include +#include +#include +#include +#include + +@class NSDistantObject; +@class NSPort; +@class NSPortNameServer; +@class NSData; + +/* + * Keys for the NSDictionary returned by [NSConnection -statistics] + */ +/* These in OPENSTEP 4.2 */ +GS_EXPORT NSString *NSConnectionRepliesReceived; +GS_EXPORT NSString *NSConnectionRepliesSent; +GS_EXPORT NSString *NSConnectionRequestsReceived; +GS_EXPORT NSString *NSConnectionRequestsSent; +/* These Are GNUstep extras */ +GS_EXPORT NSString *NSConnectionLocalCount; /* Objects sent out */ +GS_EXPORT NSString *NSConnectionProxyCount; /* Objects received */ + + + +/* + * NSConnection class interface. + * + * A few methods are in the specification but not yet implemented. + */ +@interface NSConnection : NSObject +{ +@private + BOOL _isValid; + BOOL _independentQueueing; + BOOL _authenticateIn; + BOOL _authenticateOut; + BOOL _multipleThreads; + NSPort *_receivePort; + NSPort *_sendPort; + unsigned _requestDepth; + unsigned _messageCount; + unsigned _reqOutCount; + unsigned _reqInCount; + unsigned _repOutCount; + unsigned _repInCount; +#ifndef _IN_CONNECTION_M +#define GSIMapTable void* +#endif + GSIMapTable _localObjects; + GSIMapTable _localTargets; + GSIMapTable _remoteProxies; + GSIMapTable _replyMap; +#ifndef _IN_CONNECTION_M +#undef GSIMapTable +#endif + NSTimeInterval _replyTimeout; + NSTimeInterval _requestTimeout; + NSMutableArray *_requestModes; + NSMutableArray *_runLoops; + NSMutableArray *_requestQueue; + id _delegate; + NSRecursiveLock *_refGate; + NSMutableArray *_cachedDecoders; + NSMutableArray *_cachedEncoders; + NSString *_registeredName; + NSPortNameServer *_nameServer; +} + ++ (NSArray*) allConnections; ++ (NSConnection*) connectionWithReceivePort: (NSPort*)r + sendPort: (NSPort*)s; ++ (NSConnection*) connectionWithRegisteredName: (NSString*)n + host: (NSString*)h; ++ (NSConnection*) connectionWithRegisteredName: (NSString*)n + host: (NSString*)h + usingNameServer: (NSPortNameServer*)s; ++ (id) currentConversation; ++ (NSConnection*) defaultConnection; ++ (NSDistantObject*) rootProxyForConnectionWithRegisteredName: (NSString*)name + host: (NSString*)host; ++ (NSDistantObject*) rootProxyForConnectionWithRegisteredName: (NSString*)name + host: (NSString*)host usingNameServer: (NSPortNameServer*)s; + + +- (void) addRequestMode: (NSString*)mode; +- (void) addRunLoop: (NSRunLoop*)runloop; +- (id) delegate; +- (void) enableMultipleThreads; +- (BOOL) independentConversationQueueing; +- (id) initWithReceivePort: (NSPort*)r + sendPort: (NSPort*)s; +- (void) invalidate; +- (BOOL) isValid; +- (NSArray*)localObjects; +- (BOOL) multipleThreadsEnabled; +- (NSPort*) receivePort; +- (BOOL) registerName: (NSString*)name; +- (BOOL) registerName: (NSString*)name withNameServer: (NSPortNameServer*)svr; +- (NSArray*) remoteObjects; +- (void) removeRequestMode: (NSString*)mode; +- (void) removeRunLoop: (NSRunLoop *)runloop; +- (NSTimeInterval) replyTimeout; +- (NSArray*) requestModes; +- (NSTimeInterval) requestTimeout; +- (id) rootObject; +- (NSDistantObject*) rootProxy; +- (void) runInNewThread; +- (NSPort*) sendPort; +- (void) setDelegate: anObj; +- (void) setIndependentConversationQueueing: (BOOL)flag; +- (void) setReplyTimeout: (NSTimeInterval)seconds; +- (void) setRequestMode: (NSString*)mode; +- (void) setRequestTimeout: (NSTimeInterval)seconds; +- (void) setRootObject: anObj; +- (NSDictionary*) statistics; +@end + + +/* + * This catagory contains legacy methods from the original GNU 'Connection' + * class, and useful extensions to NSConnection. + */ +@interface NSConnection (GNUstepExtensions) + ++ (NSConnection*) newRegisteringAtName: (NSString*)n + withRootObject: (id)anObject; + +- (void) gcFinalize; + +- (retval_t) forwardForProxy: (NSDistantObject*)object + selector: (SEL)sel + argFrame: (arglist_t)frame; +- (const char *) typeForSelector: (SEL)sel remoteTarget: (unsigned)target; + +@end + +GS_EXPORT NSString *ConnectionBecameInvalidNotification; + +@interface Object (NSConnectionDelegate) +/* + * This method may be used to ask a delegates permission to create + * a new connection from the old one. + * This method should be implemented in preference to the + * [makeNewConnection:sender:] which is obsolete. + */ +- (BOOL) connection: (NSConnection*)parent + shouldMakeNewConnection: (NSConnection*)newConnection; + +/* + * This is the old way of doing the same thing as + * [connection:shouldMakeNewConnection:] + * It is obsolete - don't use it. + */ +- (BOOL) makeNewConnection: (NSConnection*)newConnection + sender: (NSConnection*)parent; + +/* + * If the delegate responds to this method, it will be used to ask the + * delegate's permission to establish a new connection from the old one. + * Often this is used so that the delegate can register for invalidation + * notification on new child connections. + * This is a GNUstep extension + * Normally return newConn. + */ +- (NSConnection*) connection: (NSConnection*)ancestorConn + didConnect: (NSConnection*)newConn; + +/* + * These are like the MacOS-X delegate methods, except that we provide the + * components in mutable arrays, so that the delegate can alter the data + * items in the array. Of course, you must do that WITH CARE. + */ +- (BOOL) authenticateComponents: (NSMutableArray*)components + withData: (NSData*)authenticationData; +- (NSData*) authenticationDataForComponents: (NSMutableArray*)components; + +@end + +@interface Object (NSPortCoder) +- (Class) classForPortCoder; +/* + * Must return the class that will be created on the remote side + * of the connection. If the class to be created is not the same + * as that of the object returned by replacementObjectForPortCoder: + * then the class must be capable of recognising the object it + * actually gets in its initWithCoder: method. + * The default operation is to return NSDistantObject unless the + * object is being sent bycopy, in which case the objects actual + * class is returned. To force bycopy operation the object should + * return its own class. + */ +- (id) replacementObjectForPortCoder: (NSPortCoder*)aCoder; +/* + * This message is sent to an object about to be encoded for sending + * over the wire. The default action is to return an NSDistantObject + * which is a local proxy for the object unless the object is being + * sent bycopy, in which case the actual object is returned. + * To force bycopy, an object should return itsself. + */ + +@end + +#define CONNECTION_DEFAULT_TIMEOUT 15.0 /* in seconds */ + +/* + * NSRunLoop mode, NSNotification name and NSException strings. + */ +GS_EXPORT NSString *NSConnectionReplyMode; +GS_EXPORT NSString *NSConnectionDidDieNotification; +GS_EXPORT NSString *NSConnectionDidInitializeNotification; /* OPENSTEP */ +GS_EXPORT NSString *NSFailedAuthenticationException; /* MacOS-X */ + +#endif /* __NSConnection_h_GNUSTEP_BASE_INCLUDE */ +#else +/* Interface for GNU Objective-C version of NSConnection + Copyright (C) 1997 Free Software Foundation, Inc. + + Original by: Andrew Kachites McCallum + Version for OPENSTEP by: Richard Frith-Macdonald + Created: August 1997 + + 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 __NSConnection_h_GNUSTEP_BASE_INCLUDE +#define __NSConnection_h_GNUSTEP_BASE_INCLUDE + +#include +#include +#include +#include +#include +#include + +@class NSDistantObject; +@class NSPort; +@class NSData; + +/* + * Keys for the NSDictionary returned by [NSConnection -statistics] + */ +/* These in OPENSTEP 4.2 */ +GS_EXPORT NSString *NSConnectionRepliesReceived; +GS_EXPORT NSString *NSConnectionRepliesSent; +GS_EXPORT NSString *NSConnectionRequestsReceived; +GS_EXPORT NSString *NSConnectionRequestsSent; +/* These Are GNUstep extras */ +GS_EXPORT NSString *NSConnectionLocalCount; /* Objects sent out */ +GS_EXPORT NSString *NSConnectionProxyCount; /* Objects received */ + + +/* + * NSConnection class interface. + * + * A few methods are in the specification but not yet implemented. + */ +@interface NSConnection : NSObject +{ +@private + BOOL is_valid; + BOOL independent_queueing; + unsigned request_depth; + NSPort *receive_port; + NSPort *send_port; + unsigned message_count; + unsigned req_out_count; + unsigned req_in_count; + unsigned rep_out_count; + unsigned rep_in_count; + NSMapTable *local_objects; + NSMapTable *local_targets; + NSMapTable *remote_proxies; + NSTimeInterval reply_timeout; + NSTimeInterval request_timeout; + Class receive_port_class; + Class send_port_class; + Class encoding_class; + id delegate; + NSMutableArray *request_modes; +} + ++ (NSArray*) allConnections; ++ (NSConnection*) connectionWithRegisteredName: (NSString*)n + host: (NSString*)h; ++ (id)currentConversation; ++ (NSConnection*) defaultConnection; ++ (NSDistantObject*) rootProxyForConnectionWithRegisteredName: (NSString*)name + host: (NSString*)host; + +- (void) addRequestMode: (NSString*)mode; +- (void) addRunLoop: (NSRunLoop *)runloop; +- (id) delegate; +- (void) enableMultipleThreads; +- (BOOL) multipleThreadsEnabled; +- (BOOL) independentConversationQueueing; +- (void) invalidate; +- (BOOL) isValid; +- (BOOL) registerName: (NSString*)name; +- (NSArray *) remoteObjects; +- (void) removeRequestMode: (NSString*)mode; +- (void) removeRunLoop: (NSRunLoop *)runloop; +- (NSTimeInterval) replyTimeout; +- (NSArray*) requestModes; +- (NSTimeInterval) requestTimeout; +- (id) rootObject; +- (NSDistantObject*) rootProxy; +- (void) setDelegate: anObj; +- (void) setIndependentConversationQueueing: (BOOL)flag; +- (void) setReplyTimeout: (NSTimeInterval)seconds; +- (void) setRequestMode: (NSString*)mode; +- (void) setRequestTimeout: (NSTimeInterval)seconds; +- (void) setRootObject: anObj; +- (NSDictionary*) statistics; +@end + + +/* + * This catagory contains methods which were not in the original + * OpenStep specification, but which are in OPENSTEP. + * Some methods are not yet implemented. + */ +@interface NSConnection (OPENSTEP) ++ (NSConnection*) connectionWithReceivePort: (NSPort*)r + sendPort: (NSPort*)s; +- initWithReceivePort: (NSPort*)r + sendPort: (NSPort*)s; +- (NSPort*) receivePort; +- (void) runInNewThread; +- (NSPort*) sendPort; +@end + + +/* + * This catagory contains legacy methods from the original GNU 'Connection' + * class, and useful extensions to NSConnection. + */ +@interface NSConnection (GNUstepExtensions) + +- (void) gcFinalize; + +/* Setting and getting class configuration */ ++ (Class) defaultReceivePortClass; ++ (void) setDefaultReceivePortClass: (Class) aPortClass; ++ (Class) defaultSendPortClass; ++ (void) setDefaultSendPortClass: (Class) aPortClass; ++ (Class) defaultProxyClass; ++ (void) setDefaultProxyClass: (Class) aClass; ++ (int) defaultOutTimeout; ++ (void) setDefaultOutTimeout: (int)to; ++ (int) defaultInTimeout; ++ (void) setDefaultInTimeout: (int)to; + +/* Querying the state of all the connections */ ++ (int) messagesReceived; ++ (unsigned) connectionsCount; ++ (unsigned) connectionsCountWithInPort: (NSPort*)aPort; + +/* Registering your server object on the network. + These methods create a new connection object that must be "run" in order + to start handling requests from clients. + These method names may change when we get the capability to register + ports with names after the ports have been created. */ +/* I want the second method name to clearly indicate that we're not + connecting to a pre-existing registration name, we're registering a + new name, and this method will fail if that name has already been + registered. This is why I don't like "newWithRegisteredName:" --- + it's unclear if we're connecting to another NSConnection that already + registered with that name. */ ++ (NSConnection*) newWithRootObject: anObj; ++ (NSConnection*) newRegisteringAtName: (NSString*)n + withRootObject: anObj; ++ (NSConnection*) newRegisteringAtName: (NSString*)n + atPort: (int)portn + withRootObject: anObj; + ++ (NSConnection*) connectionByOutPort: (NSPort*)aPort; +/* Get a proxy to a remote server object. + A new connection is created if necessary. */ ++ (NSDistantObject*) rootProxyAtName: (NSString*)name onHost: (NSString*)host; ++ (NSDistantObject*) rootProxyAtName: (NSString*)name; ++ (NSDistantObject*) rootProxyAtPort: (NSPort*)anOutPort; ++ (NSDistantObject*) rootProxyAtPort: (NSPort*)anOutPort withInPort: (NSPort*)anInPort; + +/* This is the designated initializer for the NSConnection class. + You don't need to call it yourself. */ ++ (NSConnection*) newForInPort: (NSPort*)anInPort outPort: (NSPort*)anOutPort + ancestorConnection: (NSConnection*)ancestor; + +/* Make a connection object start listening for incoming requests. After + after DATE. */ +- (void) runConnectionUntilDate: date; + +/* Same as above, but never time out. */ +- (void) runConnection; + +/* When you get an invalidation notification from a connection, use + this method in order to find out if any of the proxy objects you're + using are going away. */ +- (id) proxies; + + +/* For getting the root object of a connection or port */ ++ rootObjectForInPort: (NSPort*)aPort; + +/* Used for setting the root object of a connection that we + created without one, or changing the root object of a connection + that already has one. */ ++ (void) setRootObject: anObj forInPort: (NSPort*)aPort; + +/* Querying and setting some instance variables */ +- (Class) receivePortClass; +- (Class) sendPortClass; +- (void) setReceivePortClass: (Class)aPortClass; +- (void) setSendPortClass: (Class)aPortClass; +- (Class) proxyClass; +- (Class) encodingClass; +- (Class) decodingClass; + + +/* Only subclassers and power-users need worry about these */ +- (void) addProxy: (NSDistantObject*)aProxy; +- (id) includesProxyForTarget: (gsu32)target; +- (void) removeProxy: (NSDistantObject*)aProxy; + +// It seems to be a non pure-OPENSTEP definition... +// +// new def : +- (NSArray*)localObjects; +- (void) addLocalObject: anObj; +- (id) includesLocalObject: anObj; +- (void) removeLocalObject: anObj; +- (retval_t) forwardForProxy: (NSDistantObject*)object + selector: (SEL)sel + argFrame: (arglist_t)frame; +- (const char *) typeForSelector: (SEL)sel remoteTarget: (unsigned)target; + +@end + +GS_EXPORT NSString *ConnectionBecameInvalidNotification; + +@interface Object (NSConnectionDelegate) +- (BOOL) connection: (NSConnection*)parent + shouldMakeNewConnection: (NSConnection*)newConnection; +/* + * This method may be used to ask a delegates permission to create + * a new connection from the old one. + * This method should be implemented in preference to the + * [makeNewConnection:sender:] which is obsolete. + */ +- (BOOL) makeNewConnection: (NSConnection*)newConnection + sender: (NSConnection*)parent; +/* + * This is the old way of doing the same thing as + * [connection:shouldMakeNewConnection:] + * It is obsolete - don't use it. + */ +- (NSConnection*) connection: ancestorConn didConnect: newConn; +/* + * If the delegate responds to this method, it will be used to ask the + * delegate's permission to establish a new connection from the old one. + * Often this is used so that the delegate can register for invalidation + * notification on new child connections. + * This is a GNUstep extension + * Normally return newConn. + */ +@end + +@interface Object (NSPortCoder) +- (Class) classForPortCoder; +/* + * Must return the class that will be created on the remote side + * of the connection. If the class to be created is not the same + * as that of the object returned by replacementObjectForPortCoder: + * then the class must be capable of recognising the object it + * actually gets in its initWithCoder: method. + * The default operation is to return NSDistantObject unless the + * object is being sent bycopy, in which case the objects actual + * class is returned. To force bycopy operation the object should + * return its own class. + */ +- (id) replacementObjectForPortCoder: (NSPortCoder*)aCoder; +/* + * This message is sent to an object about to be encoded for sending + * over the wire. The default action is to return an NSDistantObject + * which is a local proxy for the object unless the object is being + * sent bycopy, in which case the actual object is returned. + * To force bycopy, an object should return itsself. + */ + + +- (BOOL)authenticateComponents: (NSArray *)components + withData: (NSData *)authenticationData; +- (NSData *)authenticationDataForComponents: (NSArray *)components; + +@end + +#define CONNECTION_DEFAULT_TIMEOUT 15.0 /* in seconds */ + +/* + * NSRunLoop mode, NSNotification name and NSException strings. + */ +GS_EXPORT NSString *NSConnectionReplyMode; +GS_EXPORT NSString *NSConnectionDidDieNotification; +GS_EXPORT NSString *NSConnectionDidInitializeNotification; /* OPENSTEP */ + +/* + * For compatibility with old GNU DO code - + */ +#define RunLoopConnectionReplyMode NSConnectionReplyMode +#define ConnectionBecameInvalidNotification NSConnectionDidDieNotification +#define ConnectionWasCreatedNotification NSConnectionDidInitializeNotification + +#endif /* __NSConnection_h_GNUSTEP_BASE_INCLUDE */ +#endif diff --git a/Old/OldNSConnection.m b/Old/OldNSConnection.m new file mode 100644 index 000000000..f464e82ba --- /dev/null +++ b/Old/OldNSConnection.m @@ -0,0 +1,5072 @@ +#if GS_NEW_DO +/* Implementation of connection object for remote object messaging + Copyright (C) 1994, 1995, 1996, 1997, 2000 Free Software Foundation, Inc. + + Created by: Andrew Kachites McCallum + Date: July 1994 + Minor rewrite for OPENSTEP by: Richard Frith-Macdonald + Date: August 1997 + Major rewrite for MACOSX by: Richard Frith-Macdonald + Date: 2000 + + 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. + */ + +#include +#include +#include + +/* + * Setup for inline operation of pointer map tables. + */ +#define GSI_MAP_RETAIN_KEY(X) +#define GSI_MAP_RELEASE_KEY(X) +#define GSI_MAP_RETAIN_VAL(X) +#define GSI_MAP_RELEASE_VAL(X) +#define GSI_MAP_HASH(X) ((X).uint ^ ((X).uint >> 3)) +#define GSI_MAP_EQUAL(X,Y) ((X).ptr == (Y).ptr) + +#include + +#define _IN_CONNECTION_M +#include +#undef _IN_CONNECTION_M + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define F_LOCK(X) {NSDebugFLLog(@"GSConnection",@"Lock %@",X);[X lock];} +#define F_UNLOCK(X) {NSDebugFLLog(@"GSConnection",@"Unlock %@",X);[X unlock];} +#define M_LOCK(X) {NSDebugMLLog(@"GSConnection",@"Lock %@",X);[X lock];} +#define M_UNLOCK(X) {NSDebugMLLog(@"GSConnection",@"Unlock %@",X);[X unlock];} + +/* + * Set up a type to permit us to have direct access into an NSDistantObject + */ +typedef struct { + @defs(NSDistantObject) +} ProxyStruct; + +/* + * Cache various class pointers. + */ +static id dummyObject; +static Class connectionClass; +static Class dateClass; +static Class distantObjectClass; +static Class localCounterClass; +static Class portCoderClass; +static Class runLoopClass; + +static NSString* +stringFromMsgType(int type) +{ + switch (type) + { + case METHOD_REQUEST: + return @"method request"; + case METHOD_REPLY: + return @"method reply"; + case ROOTPROXY_REQUEST: + return @"root proxy request"; + case ROOTPROXY_REPLY: + return @"root proxy reply"; + case CONNECTION_SHUTDOWN: + return @"connection shutdown"; + case METHODTYPE_REQUEST: + return @"methodtype request"; + case METHODTYPE_REPLY: + return @"methodtype reply"; + case PROXY_RELEASE: + return @"proxy release"; + case PROXY_RETAIN: + return @"proxy retain"; + case RETAIN_REPLY: + return @"retain replay"; + default: + return @"unknown operation type!"; + } +} + +/* + * GSLocalCounter is a trivial class to keep track of how + * many different connections a particular local object is vended + * over. This is required so that we know when to remove an object + * from the global list when it is removed from the list of objects + * vended on a particular connection. + */ +@interface GSLocalCounter : NSObject +{ +@public + unsigned ref; + unsigned target; + id object; +} ++ (id) newWithObject: (id)ob; +@end + +@implementation GSLocalCounter + +static unsigned local_object_counter = 0; + ++ (id) newWithObject: (id)obj +{ + GSLocalCounter *counter; + + counter = (GSLocalCounter*)NSAllocateObject(self, 0, NSDefaultMallocZone()); + counter->ref = 1; + counter->object = RETAIN(obj); + counter->target = ++local_object_counter; + return counter; +} +- (void) dealloc +{ + RELEASE(object); + NSDeallocateObject(self); +} +@end + + + +/* + * CachedLocalObject is a trivial class to keep track of how + * many different connections a particular local object is vended + * over. This is required so that we know when to remove an object + * from the global list when it is removed from the list of objects + * vended on a particular connection. + */ +@interface CachedLocalObject : NSObject +{ + id obj; + int time; +} +- (BOOL) countdown; +- (id) obj; ++ (id) newWithObject: (id)o time: (int)t; +@end + +@implementation CachedLocalObject + ++ (id) newWithObject: (id)o time: (int)t +{ + CachedLocalObject *item; + + item = (CachedLocalObject*)NSAllocateObject(self, 0, NSDefaultMallocZone()); + item->obj = RETAIN(o); + item->time = t; + return item; +} + +- (void) dealloc +{ + RELEASE(obj); + NSDeallocateObject(self); +} + +- (BOOL) countdown +{ + if (time-- > 0) + return YES; + return NO; +} + +- (id) obj +{ + return obj; +} + +@end + + + +@interface NSConnection (Private) +- (void) handlePortMessage: (NSPortMessage*)msg; +- (void) _runInNewThread; ++ (void) setDebug: (int)val; + +- (void) addLocalObject: (NSDistantObject*)anObj; +- (NSDistantObject*) localForObject: (id)object; +- (void) removeLocalObject: (id)anObj; + +- (void) _doneInRmc: (NSPortCoder*)c; +- (NSPortCoder*) _getReplyRmc: (int)sn; +- (NSPortCoder*) _makeInRmc: (NSMutableArray*)components; +- (NSPortCoder*) _makeOutRmc: (int)sequence generate: (int*)sno reply: (BOOL)f; +- (void) _sendOutRmc: (NSPortCoder*)c type: (int)msgid; + +- (void) _service_forwardForProxy: (NSPortCoder*)rmc; +- (void) _service_release: (NSPortCoder*)rmc; +- (void) _service_retain: (NSPortCoder*)rmc; +- (void) _service_rootObject: (NSPortCoder*)rmc; +- (void) _service_shutdown: (NSPortCoder*)rmc; +- (void) _service_typeForSelector: (NSPortCoder*)rmc; +@end + +#define _proxiesGate _refGate +#define _queueGate _refGate + + +/* class defaults */ +static NSTimer *timer; + +static int debug_connection = 0; + +static NSHashTable *connection_table; +static NSLock *connection_table_gate; + +/* + * Locate an existing connection with the specified send and receive ports. + * nil ports act as wildcards and return the first match. + */ +static NSConnection* +existingConnection(NSPort *receivePort, NSPort *sendPort) +{ + NSHashEnumerator enumerator; + NSConnection *c; + + F_LOCK(connection_table_gate); + enumerator = NSEnumerateHashTable(connection_table); + while ((c = (NSConnection*)NSNextHashEnumeratorItem(&enumerator)) != nil) + { + if ((sendPort == nil || [sendPort isEqual: [c sendPort]]) + && (receivePort == nil || [receivePort isEqual: [c receivePort]])) + { + /* + * We don't want this connection to be destroyed by another thread + * between now and when it's returned from this function and used! + */ + AUTORELEASE(RETAIN(c)); + break; + } + } + F_UNLOCK(connection_table_gate); + return c; +} + +static NSMapTable *root_object_map; +static NSLock *root_object_map_gate; + +static id +rootObjectForInPort(NSPort *aPort) +{ + id rootObject; + + F_LOCK(root_object_map_gate); + rootObject = (id)NSMapGet(root_object_map, (void*)(gsaddr)aPort); + F_UNLOCK(root_object_map_gate); + return rootObject; +} + +/* Pass nil to remove any reference keyed by aPort. */ +static void +setRootObjectForInPort(id anObj, NSPort *aPort) +{ + id oldRootObject; + + F_LOCK(root_object_map_gate); + oldRootObject = (id)NSMapGet(root_object_map, (void*)(gsaddr)aPort); + if (oldRootObject != anObj) + { + if (anObj != nil) + { + NSMapInsert(root_object_map, (void*)(gsaddr)aPort, + (void*)(gsaddr)anObj); + } + else /* anObj == nil && oldRootObject != nil */ + { + NSMapRemove(root_object_map, (void*)(gsaddr)aPort); + } + } + F_UNLOCK(root_object_map_gate); +} + +static NSMapTable *objectToCounter = NULL; +static NSMapTable *targetToCounter = NULL; +static NSMapTable *targetToCached = NULL; +static NSLock *global_proxies_gate; + + + + +@implementation NSConnection + ++ (NSArray*) allConnections +{ + NSArray *a; + + M_LOCK(connection_table_gate); + a = NSAllHashTableObjects(connection_table); + M_UNLOCK(connection_table_gate); + return a; +} + ++ (NSConnection*) connectionWithReceivePort: (NSPort*)r + sendPort: (NSPort*)s +{ + NSConnection *c = existingConnection(r, s); + + if (c == nil) + { + c = [self allocWithZone: NSDefaultMallocZone()]; + c = [c initWithReceivePort: r sendPort: s]; + AUTORELEASE(c); + } + return c; +} + ++ (NSConnection*) connectionWithRegisteredName: (NSString*)n + host: (NSString*)h +{ + NSPortNameServer *s; + + s = [NSPortNameServer systemDefaultPortNameServer]; + return [self connectionWithRegisteredName: n + host: h + usingNameServer: s]; +} + ++ (NSConnection*) connectionWithRegisteredName: (NSString*)n + host: (NSString*)h + usingNameServer: (NSPortNameServer*)s +{ + NSConnection *con = nil; + + if (s != nil) + { + NSPort *sendPort = [s portForName: n onHost: h]; + + if (sendPort != nil) + { + NSPort *recvPort; + + recvPort = [[self defaultConnection] receivePort]; + con = existingConnection(recvPort, sendPort); + if (con == nil) + { + con = [self connectionWithReceivePort: recvPort + sendPort: sendPort]; + } + } + } + return con; +} + ++ (id) currentConversation +{ + [self notImplemented: _cmd]; + return self; +} + +/* + * Get the default connection for a thread. + * Possible problem - if the connection is invalidated, it won't be + * cleaned up until this thread calls this method again. The connection + * and it's ports could hang around for a very long time. + */ ++ (NSConnection*) defaultConnection +{ + static NSString *tkey = @"NSConnectionThreadKey"; + NSConnection *c; + NSMutableDictionary *d; + + d = GSCurrentThreadDictionary(); + c = (NSConnection*)[d objectForKey: tkey]; + if (c != nil && [c isValid] == NO) + { + /* + * If the default connection for this thread has been invalidated - + * release it and create a new one. + */ + [d removeObjectForKey: tkey]; + c = nil; + } + if (c == nil) + { + NSPort *port; + + c = [self alloc]; + port = [NSPort port]; + c = [c initWithReceivePort: port sendPort: nil]; + if (c != nil) + { + [d setObject: c forKey: tkey]; + RELEASE(c); + } + } + return c; +} + ++ (void) initialize +{ + if (self == [NSConnection class]) + { + connectionClass = self; + dateClass = [NSDate class]; + distantObjectClass = [NSDistantObject class]; + localCounterClass = [GSLocalCounter class]; + portCoderClass = [NSPortCoder class]; + runLoopClass = [NSRunLoop class]; + + dummyObject = [NSObject new]; + + connection_table = + NSCreateHashTable(NSNonRetainedObjectHashCallBacks, 0); + connection_table_gate = [NSLock new]; + + objectToCounter = + NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks, + NSObjectMapValueCallBacks, 0); + targetToCounter = + NSCreateMapTable(NSIntMapKeyCallBacks, + NSNonOwnedPointerMapValueCallBacks, 0); + targetToCached = + NSCreateMapTable(NSIntMapKeyCallBacks, + NSObjectMapValueCallBacks, 0); + global_proxies_gate = [NSLock new]; + root_object_map = + NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks, + NSObjectMapValueCallBacks, 0); + root_object_map_gate = [NSLock new]; + } +} + ++ (id) new +{ + /* + * Undocumented feature of OPENSTEP/MacOS-X + * +new returns the default connection. + */ + return RETAIN([self defaultConnection]); +} + ++ (NSDistantObject*) rootProxyForConnectionWithRegisteredName: (NSString*)n + host: (NSString*)h +{ + NSConnection *connection; + NSDistantObject *proxy = nil; + + connection = [self connectionWithRegisteredName: n host: h]; + if (connection != nil) + { + proxy = [connection rootProxy]; + } + + return proxy; +} + ++ (NSDistantObject*) rootProxyForConnectionWithRegisteredName: (NSString*)n + host: (NSString*)h usingNameServer: (NSPortNameServer*)s +{ + NSConnection *connection; + NSDistantObject *proxy = nil; + + connection = [self connectionWithRegisteredName: n + host: h + usingNameServer: s]; + if (connection != nil) + { + proxy = [connection rootProxy]; + } + + return proxy; +} + ++ (void) _timeout: (NSTimer*)t +{ + NSArray *cached_locals; + int i; + + cached_locals = NSAllMapTableValues(targetToCached); + for (i = [cached_locals count]; i > 0; i--) + { + CachedLocalObject *item = [cached_locals objectAtIndex: i-1]; + + if ([item countdown] == NO) + { + GSLocalCounter *counter = [item obj]; + NSMapRemove(targetToCached, (void*)counter->target); + } + } + if ([cached_locals count] == 0) + { + [t invalidate]; + timer = nil; + } +} + +- (void) addRequestMode: (NSString*)mode +{ + M_LOCK(_refGate); + if ([self isValid] == YES) + { + if ([_requestModes containsObject: mode] == NO) + { + unsigned c = [_runLoops count]; + + while (c-- > 0) + { + NSRunLoop *loop = [_runLoops objectAtIndex: c]; + + [loop addPort: _receivePort forMode: mode]; + } + [_requestModes addObject: mode]; + } + } + M_UNLOCK(_refGate); +} + +- (void) addRunLoop: (NSRunLoop*)loop +{ + M_LOCK(_refGate); + if ([self isValid] == YES) + { + if ([_runLoops indexOfObjectIdenticalTo: loop] == NSNotFound) + { + unsigned c = [_requestModes count]; + + while (c-- > 0) + { + NSString *mode = [_requestModes objectAtIndex: c]; + + [loop addPort: _receivePort forMode: mode]; + } + [_runLoops addObject: loop]; + } + } + M_UNLOCK(_refGate); +} + +- (void) dealloc +{ + if (debug_connection) + NSLog(@"deallocating 0x%x", (gsaddr)self); + [super dealloc]; +} + +- (id) delegate +{ + return GS_GC_UNHIDE(_delegate); +} + +- (void) enableMultipleThreads +{ + _multipleThreads = YES; +} + +- (BOOL) independentConversationQueueing +{ + return _independentQueueing; +} + +- (id) init +{ + /* + * Undocumented feature of OPENSTEP/MacOS-X + * -init returns the default connection. + */ + RELEASE(self); + return RETAIN([connectionClass defaultConnection]); +} + +/* This is the designated initializer for NSConnection */ +- (id) initWithReceivePort: (NSPort*)r + sendPort: (NSPort*)s +{ + NSNotificationCenter *nCenter; + NSConnection *parent; + NSConnection *conn; + NSRunLoop *loop; + id del; + NSZone *z = NSDefaultMallocZone(); + + /* + * If the receive port is nil, deallocate connection and return nil. + */ + if (r == nil) + { + if (debug_connection > 2) + { + NSLog(@"Asked to create connection with nil receive port"); + } + DESTROY(self); + return self; + } + + /* + * If the send port is nil, set it to the same as the receive port + * This connection will then only be useful to act as a server. + */ + if (s == nil) + { + s = r; + } + + conn = existingConnection(r, s); + + /* + * If the send and receive ports match an existing connection + * deallocate the new one and retain and return the old one. + */ + if (conn != nil) + { + RELEASE(self); + self = RETAIN(conn); + if (debug_connection > 2) + { + NSLog(@"Found existing connection (0x%x) for \n\t%@\n\t%@", + (gsaddr)conn, r, s); + } + return self; + } + + /* + * The parent connection is the one whose send and receive ports are + * both the same as our receive port. + */ + parent = existingConnection(r, r); + + if (debug_connection) + { + NSLog(@"Initialising new connection with parent 0x%x, 0x%x\n\t%@\n\t%@", + (gsaddr)parent, (gsaddr)self, r, s); + } + + M_LOCK(connection_table_gate); + + _isValid = YES; + _receivePort = RETAIN(r); + _sendPort = RETAIN(s); + _messageCount = 0; + _repOutCount = 0; + _reqOutCount = 0; + _repInCount = 0; + _reqInCount = 0; + + /* + * These arrays cache NSPortCoder objects + */ + _cachedDecoders = [NSMutableArray new]; + _cachedEncoders = [NSMutableArray new]; + + /* + * This is used to queue up incoming NSPortMessages representing requests + * that can't immediately be dealt with. + */ + _requestQueue = [NSMutableArray new]; + + /* + * This maps request sequence numbers to the NSPortCoder objects representing + * replies arriving from the remote connection. + */ + _replyMap = (GSIMapTable)NSZoneMalloc(z, sizeof(GSIMapTable_t)); + GSIMapInitWithZoneAndCapacity(_replyMap, z, 4); + + /* + * This maps (void*)obj to (id)obj. The obj's are retained. + * We use this instead of an NSHashTable because we only care about + * the object's address, and don't want to send the -hash message to it. + */ + _localObjects = (GSIMapTable)NSZoneMalloc(z, sizeof(GSIMapTable_t)); + GSIMapInitWithZoneAndCapacity(_localObjects, z, 4); + + /* + * This maps handles for local objects to their local proxies. + */ + _localTargets = (GSIMapTable)NSZoneMalloc(z, sizeof(GSIMapTable_t)); + GSIMapInitWithZoneAndCapacity(_localTargets, z, 4); + + /* + * This maps targets to remote proxies. + */ + _remoteProxies = (GSIMapTable)NSZoneMalloc(z, sizeof(GSIMapTable_t)); + GSIMapInitWithZoneAndCapacity(_remoteProxies, z, 4); + + _requestDepth = 0; + _delegate = nil; + _refGate = [NSRecursiveLock new]; + + /* + * Some attributes are inherited from the parent if possible. + */ + if (parent != nil) + { + unsigned count; + + _multipleThreads = parent->_multipleThreads; + _independentQueueing = parent->_independentQueueing; + _replyTimeout = parent->_replyTimeout; + _requestTimeout = parent->_requestTimeout; + _runLoops = [parent->_runLoops mutableCopy]; + count = [parent->_requestModes count]; + _requestModes = [[NSMutableArray alloc] initWithCapacity: count]; + while (count-- > 0) + { + [self addRequestMode: [parent->_requestModes objectAtIndex: count]]; + } + } + else + { + _multipleThreads = NO; + _independentQueueing = NO; + _replyTimeout = CONNECTION_DEFAULT_TIMEOUT; + _requestTimeout = CONNECTION_DEFAULT_TIMEOUT; + /* + * Set up request modes array and make sure the receiving port + * is added to the run loop to get data. + */ + loop = [runLoopClass currentRunLoop]; + _runLoops = [[NSMutableArray alloc] initWithObjects: &loop count: 1]; + _requestModes = [[NSMutableArray alloc] initWithCapacity: 2]; + [self addRequestMode: NSDefaultRunLoopMode]; + [self addRequestMode: NSConnectionReplyMode]; + + /* + * If we have no parent, we must handle incoming packets on our + * receive port ourself - so we set ourself up as the port delegate. + */ + [_receivePort setDelegate: self]; + } + + /* Ask the delegate for permission, (OpenStep-style and GNUstep-style). */ + + /* Preferred MacOS-X version, which just allows the returning of BOOL */ + del = [parent delegate]; + if ([del respondsTo: @selector(connection:shouldMakeNewConnection:)]) + { + if ([del connection: parent shouldMakeNewConnection: self] == NO) + { + M_UNLOCK(connection_table_gate); + RELEASE(self); + return nil; + } + } + /* Deprecated OpenStep version, which just allows the returning of BOOL */ + if ([del respondsTo: @selector(makeNewConnection:sender:)]) + { + if (![del makeNewConnection: self sender: parent]) + { + M_UNLOCK(connection_table_gate); + RELEASE(self); + return nil; + } + } + /* Here is the GNUstep version, which allows the delegate to specify + a substitute. Note: The delegate is responsible for freeing + newConn if it returns something different. */ + if ([del respondsTo: @selector(connection:didConnect:)]) + self = [del connection: parent didConnect: self]; + + /* Register ourselves for invalidation notification when the + ports become invalid. */ + nCenter = [NSNotificationCenter defaultCenter]; + [nCenter addObserver: self + selector: @selector(portIsInvalid:) + name: NSPortDidBecomeInvalidNotification + object: r]; + if (s != nil) + [nCenter addObserver: self + selector: @selector(portIsInvalid:) + name: NSPortDidBecomeInvalidNotification + object: s]; + + /* In order that connections may be deallocated - there is an + implementation of [-release] to automatically remove the connection + from this array when it is the only thing retaining it. */ + NSHashInsert(connection_table, (void*)self); + M_UNLOCK(connection_table_gate); + + [[NSNotificationCenter defaultCenter] + postNotificationName: NSConnectionDidInitializeNotification + object: self]; + + return self; +} + +- (void) invalidate +{ + M_LOCK(_refGate); + if (_isValid == NO) + { + M_UNLOCK(_refGate); + return; + } + _isValid = NO; + M_LOCK(connection_table_gate); + NSHashRemove(connection_table, self); + [timer invalidate]; + timer = nil; + M_UNLOCK(connection_table_gate); + + M_LOCK(_refGate); + + /* + * Don't need notifications any more - so remove self as observer. + */ + [[NSNotificationCenter defaultCenter] removeObserver: self]; + + /* + * Make sure we are not registered. + */ + [self registerName: nil]; + + /* + * Withdraw from run loops. + */ + [self setRequestMode: nil]; + + RETAIN(self); + + if (debug_connection) + { + NSLog(@"Invalidating connection 0x%x\n\t%@\n\t%@", + (gsaddr)self, _receivePort, _sendPort); + } + /* + * We need to notify any watchers of our death - but if we are already + * in the deallocation process, we can't have a notification retaining + * and autoreleasing us later once we are deallocated - so we do the + * notification with a local autorelease pool to ensure that any release + * is done before the deallocation completes. + */ + { + CREATE_AUTORELEASE_POOL(arp); + + [[NSNotificationCenter defaultCenter] + postNotificationName: NSConnectionDidDieNotification + object: self]; + RELEASE(arp); + } + + /* + * If we have been invalidated, we don't need to retain proxies + * for local objects any more. In fact, we want to get rid of + * these proxies in case they are keeping us retained when we + * might otherwise de deallocated. + */ + M_LOCK(_proxiesGate); + if (_localTargets != 0) + { + NSMutableArray *targets; + unsigned i = _localTargets->nodeCount; + GSIMapNode node; + + targets = [[NSMutableArray alloc] initWithCapacity: i]; + node = _localTargets->firstNode; + while (node != 0) + { + [targets addObject: node->value.obj]; + node = node->nextInMap; + } + while (i-- > 0) + { + id t = ((ProxyStruct*)[targets objectAtIndex: i])->_object; + + [self removeLocalObject: t]; + } + RELEASE(targets); + GSIMapEmptyMap(_localTargets); + NSZoneFree(_localTargets->zone, (void*)_localTargets); + _localTargets = 0; + } + if (_remoteProxies != 0) + { + GSIMapEmptyMap(_remoteProxies); + NSZoneFree(_remoteProxies->zone, (void*)_remoteProxies); + _remoteProxies = 0; + } + if (_localObjects != 0) + { + GSIMapNode node = _localObjects->firstNode; + + while (node != 0) + { + RELEASE(node->key.obj); + node = node->nextInMap; + } + GSIMapEmptyMap(_localObjects); + NSZoneFree(_localObjects->zone, (void*)_localObjects); + _localObjects = 0; + } + M_UNLOCK(_proxiesGate); + + RELEASE(self); +} + +- (BOOL) isValid +{ + return _isValid; +} + +- (NSArray*) localObjects +{ + NSMutableArray *c; + + /* Don't assert (_isValid); */ + M_LOCK(_proxiesGate); + if (_localObjects != 0) + { + GSIMapNode node = _localObjects->firstNode; + + c = [NSMutableArray arrayWithCapacity: _localObjects->nodeCount]; + while (node != 0) + { + [c addObject: node->key.obj]; + node = node->nextInMap; + } + } + else + { + c = [NSArray array]; + } + M_UNLOCK(_proxiesGate); + return c; +} + +- (BOOL) multipleThreadsEnabled +{ + return _multipleThreads; +} + +- (NSPort*) receivePort +{ + return _receivePort; +} + +- (BOOL) registerName: (NSString*)name +{ + NSPortNameServer *svr = [NSPortNameServer systemDefaultPortNameServer]; + + return [self registerName: name withNameServer: svr]; +} + +- (BOOL) registerName: (NSString*)name withNameServer: (NSPortNameServer*)svr +{ + BOOL result = YES; + + if (name != nil) + { + result = [svr registerPort: _receivePort forName: name]; + } + if (result == YES) + { + if (_registeredName != nil) + { + [_nameServer removePort: _receivePort forName: _registeredName]; + } + ASSIGN(_registeredName, name); + ASSIGN(_nameServer, svr); + } + return result; +} + +- (void) release +{ + /* + * If this would cause the connection to be deallocated then we + * must perform all necessary work (done in [-gcFinalize]). + * We bracket the code with a retain and release so that any + * retain/release pairs in the code won't cause recursion. + */ + if ([self retainCount] == 1) + { + [super retain]; + [self gcFinalize]; + [super release]; + } + [super release]; +} + +- (NSArray *) remoteObjects +{ + NSMutableArray *c; + + /* Don't assert (_isValid); */ + M_LOCK(_proxiesGate); + if (_remoteProxies != 0) + { + GSIMapNode node = _remoteProxies->firstNode; + + c = [NSMutableArray arrayWithCapacity: _remoteProxies->nodeCount]; + while (node != 0) + { + [c addObject: node->key.obj]; + node = node->nextInMap; + } + } + else + { + c = [NSMutableArray array]; + } + M_UNLOCK(_proxiesGate); + return c; +} + +- (void) removeRequestMode: (NSString*)mode +{ + M_LOCK(_refGate); + if (_requestModes != nil && [_requestModes containsObject: mode]) + { + unsigned c = [_runLoops count]; + + while (c-- > 0) + { + NSRunLoop *loop = [_runLoops objectAtIndex: c]; + + [loop removePort: _receivePort forMode: mode]; + } + [_requestModes removeObject: mode]; + } + M_UNLOCK(_refGate); +} + +- (void) removeRunLoop: (NSRunLoop*)loop +{ + M_LOCK(_refGate); + if (_runLoops != nil) + { + unsigned pos = [_runLoops indexOfObjectIdenticalTo: loop]; + + if (pos != NSNotFound) + { + unsigned c = [_requestModes count]; + + while (c-- > 0) + { + NSString *mode = [_requestModes objectAtIndex: c]; + + [loop removePort: _receivePort forMode: mode]; + } + [_runLoops removeObjectAtIndex: pos]; + } + } + M_UNLOCK(_refGate); +} + +- (NSTimeInterval) replyTimeout +{ + return _replyTimeout; +} + +- (NSArray*) requestModes +{ + NSArray *c; + + M_LOCK(_refGate); + c = AUTORELEASE([_requestModes copy]); + M_UNLOCK(_refGate); + return c; +} + +- (NSTimeInterval) requestTimeout +{ + return _requestTimeout; +} + +- (id) rootObject +{ + return rootObjectForInPort(_receivePort); +} + +- (NSDistantObject*) rootProxy +{ + NSPortCoder *op; + NSPortCoder *ip; + NSDistantObject *newProxy = nil; + int seq_num; + + NSParameterAssert(_receivePort); + NSParameterAssert(_isValid); + + op = [self _makeOutRmc: 0 generate: &seq_num reply: YES]; + [self _sendOutRmc: op type: ROOTPROXY_REQUEST]; + + ip = [self _getReplyRmc: seq_num]; + [ip decodeValueOfObjCType: @encode(id) at: &newProxy]; + DESTROY(ip); + return AUTORELEASE(newProxy); +} + +- (void) runInNewThread +{ + [self removeRunLoop: [runLoopClass currentRunLoop]]; + [NSThread detachNewThreadSelector: @selector(_runInNewThread) + toTarget: self + withObject: nil]; +} + +- (NSPort*) sendPort +{ + return _sendPort; +} + +- (void) setDelegate: (id)anObj +{ + _delegate = GS_GC_HIDE(anObj); + _authenticateIn = + [anObj respondsToSelector: @selector(authenticateComponents:withData:)]; + _authenticateOut = + [anObj respondsToSelector: @selector(authenticationDataForComponents:)]; +} + +- (void) setIndependentConversationQueueing: (BOOL)flag +{ + _independentQueueing = flag; +} + +- (void) setReplyTimeout: (NSTimeInterval)to +{ + _replyTimeout = to; +} + +- (void) setRequestMode: (NSString*)mode +{ + M_LOCK(_refGate); + if (_requestModes != nil) + { + while ([_requestModes count] > 0 + && [_requestModes objectAtIndex: 0] != mode) + { + [self removeRequestMode: [_requestModes objectAtIndex: 0]]; + } + while ([_requestModes count] > 1) + { + [self removeRequestMode: [_requestModes objectAtIndex: 1]]; + } + if (mode != nil && [_requestModes count] == 0) + { + [self addRequestMode: mode]; + } + } + M_UNLOCK(_refGate); +} + +- (void) setRequestTimeout: (NSTimeInterval)to +{ + _requestTimeout = to; +} + +- (void) setRootObject: (id)anObj +{ + setRootObjectForInPort(anObj, _receivePort); +} + +- (NSDictionary*) statistics +{ + NSMutableDictionary *d; + id o; + + d = [NSMutableDictionary dictionaryWithCapacity: 8]; + + M_LOCK(_refGate); + + /* + * These are in OPENSTEP 4.2 + */ + o = [NSNumber numberWithUnsignedInt: _repInCount]; + [d setObject: o forKey: NSConnectionRepliesReceived]; + o = [NSNumber numberWithUnsignedInt: _repOutCount]; + [d setObject: o forKey: NSConnectionRepliesSent]; + o = [NSNumber numberWithUnsignedInt: _reqInCount]; + [d setObject: o forKey: NSConnectionRequestsReceived]; + o = [NSNumber numberWithUnsignedInt: _reqOutCount]; + [d setObject: o forKey: NSConnectionRequestsSent]; + + /* + * These are GNUstep extras + */ + o = [NSNumber numberWithUnsignedInt: + _localTargets ? _localTargets->nodeCount : 0]; + [d setObject: o forKey: NSConnectionLocalCount]; + o = [NSNumber numberWithUnsignedInt: + _remoteProxies ? _remoteProxies->nodeCount : 0]; + [d setObject: o forKey: NSConnectionProxyCount]; + o = [NSNumber numberWithUnsignedInt: + _replyMap ? _replyMap->nodeCount : 0]; + [d setObject: o forKey: @"NSConnectionReplyQueue"]; + o = [NSNumber numberWithUnsignedInt: [_requestQueue count]]; + [d setObject: o forKey: @"NSConnectionRequestQueue"]; + + M_UNLOCK(_refGate); + + return d; +} + +@end + + + +@implementation NSConnection (GNUstepExtensions) + ++ (NSConnection*) newRegisteringAtName: (NSString*)name + withRootObject: (id)anObject +{ + NSConnection *conn; + + conn = [[self alloc] initWithReceivePort: [NSPort port] + sendPort: nil]; + [conn setRootObject: anObject]; + if ([conn registerName: name] == NO) + { + DESTROY(conn); + } + return conn; +} + +- (void) gcFinalize +{ + CREATE_AUTORELEASE_POOL(arp); + + if (debug_connection) + NSLog(@"finalising 0x%x", (gsaddr)self); + + [self invalidate]; + + /* Remove rootObject from root_object_map if this is last connection */ + if (_receivePort != nil && existingConnection(_receivePort, nil) == nil) + { + setRootObjectForInPort(nil, _receivePort); + } + + /* Remove receive port from run loop. */ + [self setRequestMode: nil]; + + DESTROY(_requestModes); + DESTROY(_runLoops); + + /* + * Finished with ports - releasing them may generate a notification + * If we are the receive port delagate, try to shift responsibility. + */ + if ([_receivePort delegate] == self) + { + NSConnection *root = existingConnection(_receivePort, _receivePort); + + if (root == nil) + { + root = existingConnection(_receivePort, nil); + } + [_receivePort setDelegate: root]; + } + DESTROY(_receivePort); + DESTROY(_sendPort); + + DESTROY(_requestQueue); + if (_replyMap != 0) + { + GSIMapNode node = _replyMap->firstNode; + + while (node != 0) + { + if (node->key.obj != dummyObject) + RELEASE(node->key.obj); + node = node->nextInMap; + } + GSIMapEmptyMap(_replyMap); + NSZoneFree(_replyMap->zone, (void*)_replyMap); + _replyMap = 0; + } + + DESTROY(_cachedDecoders); + DESTROY(_cachedEncoders); + + DESTROY(_refGate); + RELEASE(arp); +} + +/* + * NSDistantObject's -forward: : method calls this to send the message + * over the wire. + */ +- (retval_t) forwardForProxy: (NSDistantObject*)object + selector: (SEL)sel + argFrame: (arglist_t)argframe +{ + NSPortCoder *op; + BOOL outParams; + BOOL needsResponse; + const char *type; + int seq_num; + retval_t retframe; + + /* The callback for encoding the args of the method call. */ + void encoder (int argnum, void *datum, const char *type, int flags) + { +#define ENCODED_ARGNAME @"argument value" + switch (*type) + { + case _C_ID: + if (flags & _F_BYCOPY) + [op encodeBycopyObject: *(id*)datum]; +#ifdef _F_BYREF + else if (flags & _F_BYREF) + [op encodeByrefObject: *(id*)datum]; +#endif + else + [op encodeObject: *(id*)datum]; + break; + default: + [op encodeValueOfObjCType: type at: datum]; + } + } + + /* Encode the method on an RMC, and send it. */ + + NSParameterAssert (_isValid); + + /* get the method types from the selector */ +#if NeXT_runtime + [NSException + raise: NSGenericException + format: @"Sorry, distributed objects does not work with NeXT runtime"]; + /* type = [object selectorTypeForProxy: sel]; */ +#else + type = sel_get_type(sel); +#endif + if (type == 0 || *type == '\0') + { + type = [[object methodSignatureForSelector: sel] methodType]; + if (type) + { + sel_register_typed_name(sel_get_name(sel), type); + } + } + NSParameterAssert(type); + NSParameterAssert(*type); + + op = [self _makeOutRmc: 0 generate: &seq_num reply: YES]; + + if (debug_connection > 4) + NSLog(@"building packet seq %d", seq_num); + + /* Send the types that we're using, so that the performer knows + exactly what qualifiers we're using. + If all selectors included qualifiers, and if I could make + sel_types_match() work the way I wanted, we wouldn't need to do + this. */ + [op encodeValueOfObjCType: @encode(char*) at: &type]; + + /* xxx This doesn't work with proxies and the NeXT runtime because + type may be a method_type from a remote machine with a + different architecture, and its argframe layout specifiers + won't be right for this machine! */ + outParams = mframe_dissect_call (argframe, type, encoder); + + if (outParams == YES) + { + needsResponse = YES; + } + else + { + int flags; + + needsResponse = NO; + flags = objc_get_type_qualifiers(type); + if ((flags & _F_ONEWAY) == 0) + { + needsResponse = YES; + } + else + { + const char *tmptype = objc_skip_type_qualifiers(type); + + if (*tmptype != _C_VOID) + { + needsResponse = YES; + } + } + } + + [self _sendOutRmc: op type: METHOD_REQUEST]; + NSDebugMLLog(@"NSConnection", @"Sent message to 0x%x", (gsaddr)self); + + if (needsResponse == NO) + { + /* + * Since we don't need a response, we can remove the placeholder from + * the _replyMap. + */ + M_LOCK(_refGate); + GSIMapRemoveKey(_replyMap, (GSIMapKey)seq_num); + M_UNLOCK(_refGate); + retframe = alloca(sizeof(void*)); /* Dummy value for void return. */ + } + else + { + NSPortCoder *ip = nil; + BOOL is_exception = NO; + + void decoder(int argnum, void *datum, const char *type, int flags) + { + if (type == 0) + { + if (ip != nil) + { + DESTROY(ip); + /* this must be here to avoid trashing alloca'ed retframe */ + ip = (id)-1; + _repInCount++; /* received a reply */ + } + return; + } + /* If we didn't get the reply packet yet, get it now. */ + if (!ip) + { + if (!_isValid) + { + [NSException raise: NSGenericException + format: @"connection waiting for request was shut down"]; + } + ip = [self _getReplyRmc: seq_num]; + /* + * Find out if the server is returning an exception instead + * of the return values. + */ + [ip decodeValueOfObjCType: @encode(BOOL) at: &is_exception]; + if (is_exception) + { + /* Decode the exception object, and raise it. */ + id exc; + [ip decodeValueOfObjCType: @encode(id) at: &exc]; + DESTROY(ip); + ip = (id)-1; + /* xxx Is there anything else to clean up in + dissect_method_return()? */ + [exc raise]; + } + } + [ip decodeValueOfObjCType: type at: datum]; + /* -decodeValueOfObjCType:at: malloc's new memory + for pointers. We need to make sure it gets freed eventually + so we don't have a memory leak. Request here that it be + autorelease'ed. Also autorelease created objects. */ + if ((*type == _C_CHARPTR || *type == _C_PTR) && *(void**)datum != 0) + [NSData dataWithBytesNoCopy: *(void**)datum length: 1]; + else if (*type == _C_ID) + AUTORELEASE(*(id*)datum); + } + + retframe = mframe_build_return (argframe, type, outParams, decoder); + /* Make sure we processed all arguments, and dismissed the IP. + IP is always set to -1 after being dismissed; the only places + this is done is in this function DECODER(). IP will be nil + if mframe_build_return() never called DECODER(), i.e. when + we are just returning (void).*/ + NSAssert(ip == (id)-1 || ip == nil, NSInternalInconsistencyException); + } + return retframe; +} + +- (const char *) typeForSelector: (SEL)sel remoteTarget: (unsigned)target +{ + id op, ip; + char *type = 0; + int seq_num; + + NSParameterAssert(_receivePort); + NSParameterAssert (_isValid); + op = [self _makeOutRmc: 0 generate: &seq_num reply: YES]; + [op encodeValueOfObjCType: ":" at: &sel]; + [op encodeValueOfObjCType: @encode(unsigned) at: &target]; + [self _sendOutRmc: op type: METHODTYPE_REQUEST]; + ip = [self _getReplyRmc: seq_num]; + [ip decodeValueOfObjCType: @encode(char*) at: &type]; + DESTROY(ip); + return type; +} + + +/* Class-wide stats and collections. */ + ++ (unsigned) connectionsCount +{ + unsigned result; + + M_LOCK(connection_table_gate); + result = NSCountHashTable(connection_table); + M_UNLOCK(connection_table_gate); + return result; +} + ++ (unsigned) connectionsCountWithInPort: (NSPort*)aPort +{ + unsigned count = 0; + NSHashEnumerator enumerator; + NSConnection *o; + + M_LOCK(connection_table_gate); + enumerator = NSEnumerateHashTable(connection_table); + while ((o = (NSConnection*)NSNextHashEnumeratorItem(&enumerator)) != nil) + { + if ([aPort isEqual: [o receivePort]]) + { + count++; + } + } + M_UNLOCK(connection_table_gate); + + return count; +} + +@end + + + + + +@implementation NSConnection (Private) + +- (void) handlePortMessage: (NSPortMessage*)msg +{ + NSPortCoder *rmc; + int type = [msg msgid]; + NSMutableArray *components = [msg _components]; + NSPort *rp = [msg receivePort]; + NSPort *sp = [msg sendPort]; + NSConnection *conn; + + if (debug_connection > 4) + { + NSLog(@"handling packet of type %d (%@)", type, stringFromMsgType(type)); + } + conn = [connectionClass connectionWithReceivePort: rp sendPort: sp]; + if (conn == nil) + { + NSLog(@"received port message for unknown connection - %@", msg); + return; + } + else if ([conn isValid] == NO) + { + if (debug_connection) + { + NSLog(@"received port message for invalid connection - %@", msg); + } + return; + } + + if (conn->_authenticateIn == YES + && (type == METHOD_REQUEST || type == METHOD_REPLY)) + { + NSData *d; + unsigned count = [components count]; + + d = RETAIN([components objectAtIndex: --count]); + [components removeObjectAtIndex: count]; + if ([[conn delegate] authenticateComponents: components + withData: d] == NO) + { + RELEASE(d); + [NSException raise: NSFailedAuthenticationException + format: @"message not authenticated by delegate"]; + } + RELEASE(d); + } + + rmc = [conn _makeInRmc: components]; + + switch (type) + { + case ROOTPROXY_REQUEST: + /* It won't take much time to handle this, so go ahead and service + it, even if we are waiting for a reply. */ + [conn _service_rootObject: rmc]; + break; + + case METHODTYPE_REQUEST: + /* It won't take much time to handle this, so go ahead and service + it, even if we are waiting for a reply. */ + [conn _service_typeForSelector: rmc]; + break; + + case METHOD_REQUEST: + /* + * We just got a new request; we need to decide whether to queue + * it or service it now. + * If the REPLY_DEPTH is 0, then we aren't in the middle of waiting + * for a reply, we are waiting for requests---so service it now. + * If REPLY_DEPTH is non-zero, we may still want to service it now + * if independent_queuing is NO. + */ + M_LOCK(conn->_queueGate); + if (conn->_requestDepth == 0 || conn->_independentQueueing == NO) + { + conn->_requestDepth++; + M_UNLOCK(conn->_queueGate); + [conn _service_forwardForProxy: rmc]; + M_LOCK(conn->_queueGate); + conn->_requestDepth--; + } + else + { + [conn->_requestQueue addObject: rmc]; + } + /* + * Service any requests that were queued while we + * were waiting for replies. + */ + while (conn->_requestDepth == 0 && [conn->_requestQueue count] > 0) + { + rmc = [conn->_requestQueue objectAtIndex: 0]; + [conn->_requestQueue removeObjectAtIndex: 0]; + M_UNLOCK(conn->_queueGate); + [conn _service_forwardForProxy: rmc]; + M_LOCK(conn->_queueGate); + } + M_UNLOCK(conn->_queueGate); + break; + + /* + * For replies, we read the sequence number from the reply object and + * store it in a map using thee sequence number as the key. That way + * it's easy for the connection to find replies by their numbers. + */ + case ROOTPROXY_REPLY: + case METHOD_REPLY: + case METHODTYPE_REPLY: + case RETAIN_REPLY: + { + int sequence; + GSIMapNode node; + + [rmc decodeValueOfObjCType: @encode(int) at: &sequence]; + M_LOCK(conn->_queueGate); + node = GSIMapNodeForKey(conn->_replyMap, (GSIMapKey)sequence); + if (node == 0) + { + NSDebugMLLog(@"NSConnection", @"Ignoring RMC %d", sequence); + RELEASE(rmc); + } + else if (node->value.obj == dummyObject) + { + node->value.obj = rmc; + } + else + { + NSDebugMLLog(@"NSConnection", @"Replace RMC %d", sequence); + RELEASE(node->value.obj); + node->value.obj = rmc; + } + M_UNLOCK(conn->_queueGate); + } + break; + + case CONNECTION_SHUTDOWN: + { + [conn _service_shutdown: rmc]; + break; + } + case PROXY_RELEASE: + { + [conn _service_release: rmc]; + break; + } + case PROXY_RETAIN: + { + [conn _service_retain: rmc]; + break; + } + default: + [NSException raise: NSGenericException + format: @"unrecognized NSPortCoder identifier"]; + } +} + +- (void) _runInNewThread +{ + NSRunLoop *loop = [runLoopClass currentRunLoop]; + + [self addRunLoop: loop]; + [loop run]; +} + ++ (void) setDebug: (int)val +{ + debug_connection = val; +} + +/* NSConnection calls this to service the incoming method request. */ +- (void) _service_forwardForProxy: (NSPortCoder*)aRmc +{ + char *forward_type = 0; + id op = nil; + int reply_sno; + + void decoder (int argnum, void *datum, const char *type) + { + /* We need this "dismiss" to happen here and not later so that Coder + "-awake..." methods will get sent before the __builtin_apply! */ + if (argnum == -1 && datum == 0 && type == 0) + { + [self _doneInRmc: aRmc]; + return; + } + + [aRmc decodeValueOfObjCType: type at: datum]; + /* -decodeValueOfObjCType: at: malloc's new memory + for char*'s. We need to make sure it gets freed eventually + so we don't have a memory leak. Request here that it be + autorelease'ed. Also autorelease created objects. */ + if ((*type == _C_CHARPTR || *type == _C_PTR) && *(void**)datum != 0) + [NSData dataWithBytesNoCopy: *(void**)datum length: 1]; + else if (*type == _C_ID) + AUTORELEASE(*(id*)datum); + } + + void encoder (int argnum, void *datum, const char *type, int flags) + { +#define ENCODED_RETNAME @"return value" + if (op == nil) + { + BOOL is_exception = NO; + /* It is possible that our connection died while the method was + being called - in this case we mustn't try to send the result + back to the remote application! */ + if (!_isValid) + return; + op = [self _makeOutRmc: reply_sno generate: 0 reply: NO]; + [op encodeValueOfObjCType: @encode(BOOL) at: &is_exception]; + } + switch (*type) + { + case _C_ID: + if (flags & _F_BYCOPY) + [op encodeBycopyObject: *(id*)datum]; +#ifdef _F_BYREF + else if (flags & _F_BYREF) + [op encodeByrefObject: *(id*)datum]; +#endif + else + [op encodeObject: *(id*)datum]; + break; + default: + [op encodeValueOfObjCType: type at: datum]; + } + } + + /* Make sure don't let exceptions caused by servicing the client's + request cause us to crash. */ + NS_DURING + { + NSParameterAssert (_isValid); + + /* Save this for later */ + [aRmc decodeValueOfObjCType: @encode(int) at: &reply_sno]; + + /* Get the types that we're using, so that we know + exactly what qualifiers the forwarder used. + If all selectors included qualifiers and I could make + sel_types_match() work the way I wanted, we wouldn't need + to do this. */ + [aRmc decodeValueOfObjCType: @encode(char*) at: &forward_type]; + + if (debug_connection > 1) + NSLog(@"Handling message from 0x%x", (gsaddr)self); + _reqInCount++; /* Handling an incoming request. */ + mframe_do_call (forward_type, decoder, encoder); + if (op != nil) + { + [self _sendOutRmc: op type: METHOD_REPLY]; + } + } + + /* Make sure we pass all exceptions back to the requestor. */ + NS_HANDLER + { + BOOL is_exception = YES; + + /* Send the exception back to the client. */ + if (_isValid) + { + NS_DURING + { + op = [self _makeOutRmc: reply_sno generate: 0 reply: NO]; + [op encodeValueOfObjCType: @encode(BOOL) + at: &is_exception]; + [op encodeBycopyObject: localException]; + [self _sendOutRmc: op type: METHOD_REPLY]; + } + NS_HANDLER + { + NSLog(@"Exception when sending exception back to client - %@", + localException); + } + NS_ENDHANDLER; + } + } + NS_ENDHANDLER; + if (forward_type != 0) + { + NSZoneFree(NSDefaultMallocZone(), forward_type); + } +} + +- (void) _service_rootObject: (NSPortCoder*)rmc +{ + id rootObject = rootObjectForInPort(_receivePort); + int sequence; + NSPortCoder *op; + + NSParameterAssert(_receivePort); + NSParameterAssert(_isValid); + NSParameterAssert([rmc connection] == self); + + [rmc decodeValueOfObjCType: @encode(int) at: &sequence]; + [self _doneInRmc: rmc]; + op = [self _makeOutRmc: sequence generate: 0 reply: NO]; + [op encodeObject: rootObject]; + [self _sendOutRmc: op type: ROOTPROXY_REPLY]; +} + +- (void) _service_release: (NSPortCoder*)rmc +{ + unsigned int count; + unsigned int pos; + int sequence; + + NSParameterAssert (_isValid); + + [rmc decodeValueOfObjCType: @encode(int) at: &sequence]; + [rmc decodeValueOfObjCType: @encode(typeof(count)) at: &count]; + + for (pos = 0; pos < count; pos++) + { + unsigned target; + NSDistantObject *prox; + + [rmc decodeValueOfObjCType: @encode(typeof(target)) at: &target]; + + prox = (NSDistantObject*)[self includesLocalTarget: target]; + if (prox != nil) + { + if (debug_connection > 3) + NSLog(@"releasing object with target (0x%x) on (0x%x)", + target, (gsaddr)self); + [self removeLocalObject: ((ProxyStruct*)prox)->_object]; + } + else if (debug_connection > 3) + NSLog(@"releasing object with target (0x%x) on (0x%x) - nothing to do", + target, (gsaddr)self); + } + [self _doneInRmc: rmc]; +} + +- (void) _service_retain: (NSPortCoder*)rmc +{ + unsigned target; + NSPortCoder *op; + int sequence; + + NSParameterAssert (_isValid); + + [rmc decodeValueOfObjCType: @encode(int) at: &sequence]; + op = [self _makeOutRmc: sequence generate: 0 reply: NO]; + + [rmc decodeValueOfObjCType: @encode(typeof(target)) at: &target]; + [self _doneInRmc: rmc]; + + if (debug_connection > 3) + NSLog(@"looking to retain local object with target (0x%x) on (0x%x)", + target, (gsaddr)self); + + if ([self includesLocalTarget: target] == nil) + { + GSLocalCounter *counter; + + M_LOCK(global_proxies_gate); + counter = NSMapGet (targetToCounter, (void*)target); + if (counter == nil) + { + /* + * If the target doesn't exist for any connection, but still + * persists in the cache (ie it was recently released) then + * we move it back from the cache to the main maps so we can + * retain it on this connection. + */ + counter = NSMapGet (targetToCached, (void*)target); + if (counter) + { + unsigned t = counter->target; + id o = counter->object; + + NSMapInsert(objectToCounter, (void*)o, counter); + NSMapInsert(targetToCounter, (void*)t, counter); + NSMapRemove(targetToCached, (void*)t); + if (debug_connection > 3) + NSLog(@"target (0x%x) moved from cache", target); + } + } + M_UNLOCK(global_proxies_gate); + if (counter == nil) + { + [op encodeObject: @"target not found anywhere"]; + if (debug_connection > 3) + NSLog(@"target (0x%x) not found anywhere for retain", target); + } + else + { + [distantObjectClass proxyWithLocal: counter->object + connection: self]; + [op encodeObject: nil]; + if (debug_connection > 3) + NSLog(@"retained object (0x%x) target (0x%x) on connection(0x%x)", + counter->object, counter->target, self); + } + } + else + { + [op encodeObject: nil]; + if (debug_connection > 3) + NSLog(@"target (0x%x) already retained on connection (0x%x)", + target, self); + } + + [self _sendOutRmc: op type: RETAIN_REPLY]; +} + +- (void) shutdown +{ + NSPortCoder *op; + int sno; + + NSParameterAssert(_receivePort); + NSParameterAssert (_isValid); + op = [self _makeOutRmc: 0 generate: &sno reply: NO]; + [self _sendOutRmc: op type: CONNECTION_SHUTDOWN]; +} + +- (void) _service_shutdown: (NSPortCoder*)rmc +{ + NSParameterAssert (_isValid); + [self _doneInRmc: rmc]; + [self invalidate]; + [NSException raise: NSGenericException + format: @"connection waiting for request was shut down"]; +} + +- (void) _service_typeForSelector: (NSPortCoder*)rmc +{ + NSPortCoder *op; + unsigned target; + NSDistantObject *p; + int sequence; + id o; + SEL sel; + const char *type; + struct objc_method* m; + + NSParameterAssert(_receivePort); + NSParameterAssert (_isValid); + + [rmc decodeValueOfObjCType: @encode(int) at: &sequence]; + op = [self _makeOutRmc: sequence generate: 0 reply: NO]; + + [rmc decodeValueOfObjCType: ":" at: &sel]; + [rmc decodeValueOfObjCType: @encode(unsigned) at: &target]; + [self _doneInRmc: rmc]; + p = [self includesLocalTarget: target]; + o = ((ProxyStruct*)p)->_object; + + /* xxx We should make sure that TARGET is a valid object. */ + /* Not actually a Proxy, but we avoid the warnings "id" would have made. */ + m = class_get_instance_method(((NSDistantObject*)o)->isa, sel); + /* Perhaps I need to be more careful in the line above to get the + version of the method types that has the type qualifiers in it. + Search the protocols list. */ + if (m) + type = m->method_types; + else + type = ""; + [op encodeValueOfObjCType: @encode(char*) at: &type]; + [self _sendOutRmc: op type: METHODTYPE_REPLY]; +} + + + +/* + * Check the queue, then try to get it from the network by waiting + * while we run the NSRunLoop. Raise exception if we don't get anything + * before timing out. + */ +- _getReplyRmc: (int)sn +{ + NSPortCoder *rmc; + GSIMapNode node; + NSDate *timeout_date = nil; + + M_LOCK(_queueGate); + while ((node = GSIMapNodeForKey(_replyMap, (GSIMapKey)sn)) != 0 + && node->value.obj == dummyObject) + { + if (timeout_date == nil) + { + timeout_date = [dateClass allocWithZone: NSDefaultMallocZone()]; + timeout_date + = [timeout_date initWithTimeIntervalSinceNow: _replyTimeout]; + } + M_UNLOCK(_queueGate); + if ([runLoopClass runOnceBeforeDate: timeout_date + forMode: NSConnectionReplyMode] == NO) + { + M_LOCK(_queueGate); + node = GSIMapNodeForKey(_replyMap, (GSIMapKey)sn); + break; + } + M_LOCK(_queueGate); + } + if (node == 0) + { + rmc = nil; + } + else + { + rmc = node->value.obj; + GSIMapRemoveKey(_replyMap, (GSIMapKey)sn); + } + M_UNLOCK(_queueGate); + TEST_RELEASE(timeout_date); + if (rmc == nil) + { + [NSException raise: NSInternalInconsistencyException + format: @"no reply message available"]; + } + if (rmc == dummyObject) + { + [NSException raise: NSPortTimeoutException + format: @"timed out waiting for reply"]; + } + return rmc; +} + +- (void) _doneInRmc: (NSPortCoder*)c +{ + M_LOCK(_refGate); + [_cachedDecoders addObject: c]; + [c dispatch]; /* Tell NSPortCoder to release the connection. */ + RELEASE(c); + M_UNLOCK(_refGate); +} + +- (NSPortCoder*) _makeInRmc: (NSMutableArray*)components +{ + NSPortCoder *coder; + unsigned count; + + NSParameterAssert(_isValid); + + M_LOCK(_refGate); + count = [_cachedDecoders count]; + if (count > 0) + { + coder = [_cachedDecoders objectAtIndex: --count]; + RETAIN(coder); + [_cachedDecoders removeObjectAtIndex: count]; + } + else + { + coder = [portCoderClass allocWithZone: NSDefaultMallocZone()]; + } + M_UNLOCK(_refGate); + + coder = [coder initWithReceivePort: _receivePort + sendPort: _sendPort + components: components]; + return coder; +} + +/* + * Create an NSPortCoder object for encoding an outgoing message or reply. + * + * sno Is the seqence number to encode into the coder. + * ret If non-null, generate a new sequence number and return it + * here. Ignore the sequence number passed in sno. + * rep If this flag is YES, add a placeholder to the _replyMap + * so we handle an incoming reply for this sequence number. + */ +- (NSPortCoder*) _makeOutRmc: (int)sno generate: (int*)ret reply: (BOOL)rep +{ + NSPortCoder *coder; + unsigned count; + + NSParameterAssert(_isValid); + + M_LOCK(_refGate); + /* + * Generate a new sequence number if required. + */ + if (ret != 0) + { + sno = _messageCount++; + *ret = sno; + } + /* + * Add a placeholder to the reply map if we expect a reply. + */ + if (rep == YES) + { + GSIMapAddPair(_replyMap, (GSIMapKey)sno, (GSIMapVal)dummyObject); + } + /* + * Locate or create an rmc + */ + count = [_cachedEncoders count]; + if (count > 0) + { + coder = [_cachedEncoders objectAtIndex: --count]; + RETAIN(coder); + [_cachedEncoders removeObjectAtIndex: count]; + } + else + { + coder = [portCoderClass allocWithZone: NSDefaultMallocZone()]; + } + M_UNLOCK(_refGate); + + coder = [coder initWithReceivePort: _receivePort + sendPort: _sendPort + components: nil]; + [coder encodeValueOfObjCType: @encode(int) at: &sno]; + return coder; +} + +- (void) _sendOutRmc: (NSPortCoder*)c type: (int)msgid +{ + NSDate *limit; + BOOL sent = NO; + BOOL raiseException = NO; + BOOL needsReply = NO; + NSMutableArray *components = [c _components]; + + if (_authenticateOut == YES + && (msgid == METHOD_REQUEST || msgid == METHOD_REPLY)) + { + NSData *d; + + d = [[self delegate] authenticationDataForComponents: components]; + if (d == nil) + { + RELEASE(c); + [NSException raise: NSGenericException + format: @"Bad authentication data provided by delegate"]; + } + [components addObject: d]; + } + + switch (msgid) + { + case PROXY_RETAIN: + needsReply = YES; + case CONNECTION_SHUTDOWN: + case METHOD_REPLY: + case ROOTPROXY_REPLY: + case METHODTYPE_REPLY: + case PROXY_RELEASE: + case RETAIN_REPLY: + raiseException = NO; + break; + + case METHOD_REQUEST: + case ROOTPROXY_REQUEST: + case METHODTYPE_REQUEST: + needsReply = YES; + default: + raiseException = YES; + break; + } + + limit = [dateClass dateWithTimeIntervalSinceNow: _requestTimeout]; + sent = [_sendPort sendBeforeDate: limit + msgid: msgid + components: components + from: _receivePort + reserved: [_sendPort reservedSpaceLength]]; + + M_LOCK(_refGate); + /* + * If we have sent out a request on a run loop that we don't already + * know about, it must be on a new thread - so if we have multipleThreads + * enabled, we must add the run loop of the new thread so that we can + * get the reply in this thread. + */ + if (_multipleThreads == YES && needsReply == YES) + { + NSRunLoop *loop = [runLoopClass currentRunLoop]; + + if ([_runLoops indexOfObjectIdenticalTo: loop] == NSNotFound) + { + [self addRunLoop: loop]; + } + } + + /* + * We replace the code we have just used in the cache, and tell it not to + * retain this connection any more. + */ + [_cachedEncoders addObject: c]; + [c dispatch]; /* Tell NSPortCoder to release the connection. */ + RELEASE(c); + M_UNLOCK(_refGate); + + if (sent == NO) + { + NSString *text = stringFromMsgType(msgid); + + if ([_sendPort isValid] == NO) + { + text = [text stringByAppendingFormat: @" - port was invalidated"]; + } + if (raiseException == YES) + { + [NSException raise: NSPortTimeoutException format: text]; + } + else + { + NSLog(@"Port operation timed out - %@", text); + } + } + else + { + switch (msgid) + { + case METHOD_REQUEST: + _reqOutCount++; /* Sent a request. */ + break; + case METHOD_REPLY: + _repOutCount++; /* Sent back a reply. */ + break; + default: + break; + } + } +} + + + +/* Managing objects and proxies. */ +- (void) addLocalObject: (NSDistantObject*)anObj +{ + id object; + unsigned target; + GSLocalCounter *counter; + GSIMapNode node; + + M_LOCK(_proxiesGate); + M_LOCK(global_proxies_gate); + NSParameterAssert (_isValid); + + /* + * Record the value in the _localObjects map, retaining it. + */ + object = ((ProxyStruct*)anObj)->_object; + node = GSIMapNodeForKey(_localObjects, (GSIMapKey)object); + IF_NO_GC(RETAIN(anObj)); + if (node == 0) + { + GSIMapAddPair(_localObjects, (GSIMapKey)object, (GSIMapVal)anObj); + } + else + { + RELEASE(node->value.obj); + node->value.obj = anObj; + } + + /* + * Keep track of local objects accross all connections. + */ + counter = NSMapGet(objectToCounter, (void*)object); + if (counter) + { + counter->ref++; + target = counter->target; + } + else + { + counter = [localCounterClass newWithObject: object]; + target = counter->target; + NSMapInsert(objectToCounter, (void*)object, counter); + NSMapInsert(targetToCounter, (void*)target, counter); + RELEASE(counter); + } + ((ProxyStruct*)anObj)->_handle = target; + GSIMapAddPair(_localTargets, (GSIMapKey)target, (GSIMapVal)anObj); + if (debug_connection > 2) + NSLog(@"add local object (0x%x) target (0x%x) " + @"to connection (0x%x) (ref %d)", + (gsaddr)object, target, (gsaddr) self, counter->ref); + M_UNLOCK(global_proxies_gate); + M_UNLOCK(_proxiesGate); +} + +- (NSDistantObject*) localForObject: (id)object +{ + GSIMapNode node; + NSDistantObject *p; + + /* Don't assert (_isValid); */ + M_LOCK(_proxiesGate); + node = GSIMapNodeForKey(_localObjects, (GSIMapKey)object); + if (node == 0) + { + p = nil; + } + else + { + p = node->value.obj; + } + M_UNLOCK(_proxiesGate); + NSParameterAssert(p == nil || [p connectionForProxy] == self); + return p; +} + +- (void) removeLocalObject: (id)anObj +{ + NSDistantObject *prox; + unsigned target; + GSLocalCounter *counter; + unsigned val = 0; + GSIMapNode node; + + M_LOCK(global_proxies_gate); + M_LOCK(_proxiesGate); + + node = GSIMapNodeForKey(_localObjects, (GSIMapKey)anObj); + if (node == 0) + { + prox = nil; + } + else + { + prox = node->value.obj; + } + target = ((ProxyStruct*)prox)->_handle; + + /* + * If all references to a local proxy have gone - remove the + * global reference as well. + */ + counter = NSMapGet(objectToCounter, (void*)anObj); + if (counter) + { + counter->ref--; + if ((val = counter->ref) == 0) + { + /* + * If this proxy has been vended onwards by another process, we + * need to keep a reference to the local object around for a + * while in case that other process needs it. + */ + if (0) + { + id item; + if (timer == nil) + { + timer = [NSTimer scheduledTimerWithTimeInterval: 1.0 + target: connectionClass + selector: @selector(_timeout:) + userInfo: nil + repeats: YES]; + } + item = [CachedLocalObject newWithObject: counter time: 30]; + NSMapInsert(targetToCached, (void*)target, item); + RELEASE(item); + if (debug_connection > 3) + NSLog(@"placed local object (0x%x) target (0x%x) in cache", + (gsaddr)anObj, target); + } + NSMapRemove(objectToCounter, (void*)anObj); + NSMapRemove(targetToCounter, (void*)target); + } + } + + /* + * Remove the proxy from _localObjects and release it. + */ + GSIMapRemoveKey(_localObjects, (GSIMapKey)anObj); + RELEASE(prox); + + /* + * Remove the target info too - no release required. + */ + GSIMapRemoveKey(_localTargets, (GSIMapKey)target); + + if (debug_connection > 2) + NSLog(@"remove local object (0x%x) target (0x%x) " + @"from connection (0x%x) (ref %d)", + (gsaddr)anObj, target, (gsaddr)self, val); + + M_UNLOCK(_proxiesGate); + M_UNLOCK(global_proxies_gate); +} + +- (void) _release_targets: (unsigned*)list count: (unsigned)number +{ + NS_DURING + { + /* + * Tell the remote app that it can release its local objects + * for the targets in the specified list since we don't have + * proxies for them any more. + */ + if (_receivePort != nil && _isValid == YES && number > 0) + { + id op; + unsigned i; + int sequence; + + op = [self _makeOutRmc: 0 generate: &sequence reply: NO]; + + [op encodeValueOfObjCType: @encode(unsigned) at: &number]; + + for (i = 0; i < number; i++) + { + [op encodeValueOfObjCType: @encode(unsigned) at: &list[i]]; + if (debug_connection > 3) + NSLog(@"sending release for target (0x%x) on (0x%x)", + list[i], (gsaddr)self); + } + + [self _sendOutRmc: op type: PROXY_RELEASE]; + } + } + NS_HANDLER + { + if (debug_connection) + NSLog(@"failed to release targets - %@", localException); + } + NS_ENDHANDLER +} + +- (void) retainTarget: (unsigned)target +{ + NS_DURING + { + /* + * Tell the remote app that it must retain the local object + * for the target on this connection. + */ + if (_receivePort && _isValid) + { + NSPortCoder *op; + id ip; + id result; + int seq_num; + + op = [self _makeOutRmc: 0 generate: &seq_num reply: YES]; + [op encodeValueOfObjCType: @encode(typeof(target)) at: &target]; + [self _sendOutRmc: op type: PROXY_RETAIN]; + + ip = [self _getReplyRmc: seq_num]; + [ip decodeValueOfObjCType: @encode(id) at: &result]; + DESTROY(ip); + if (result != nil) + NSLog(@"failed to retain target - %@", result); + } + } + NS_HANDLER + { + NSLog(@"failed to retain target - %@", localException); + } + NS_ENDHANDLER +} + +- (void) removeProxy: (NSDistantObject*)aProxy +{ + M_LOCK(_proxiesGate); + if (_isValid == YES) + { + unsigned target; + GSIMapNode node; + + target = ((ProxyStruct*)aProxy)->_handle; + node = GSIMapNodeForKey(_remoteProxies, (GSIMapKey)target); + if (node != 0) + { + RELEASE(node->value.obj); + GSIMapRemoveKey(_remoteProxies, (GSIMapKey)target); + } + /* + * Tell the remote application that we have removed our proxy and + * it can release it's local object. + */ + [self _release_targets: &target count: 1]; + } + M_UNLOCK(_proxiesGate); +} + +- (NSDistantObject*) proxyForTarget: (unsigned)target +{ + NSDistantObject *p; + GSIMapNode node; + + /* Don't assert (_isValid); */ + M_LOCK(_proxiesGate); + node = GSIMapNodeForKey(_remoteProxies, (GSIMapKey)target); + if (node == 0) + { + p = nil; + } + else + { + p = node->value.obj; + } + M_UNLOCK(_proxiesGate); + return p; +} + +- (void) addProxy: (NSDistantObject*) aProxy +{ + unsigned target; + GSIMapNode node; + + M_LOCK(_proxiesGate); + NSParameterAssert(_isValid); + NSParameterAssert(aProxy->isa == distantObjectClass); + NSParameterAssert([aProxy connectionForProxy] == self); + target = ((ProxyStruct*)aProxy)->_handle; + node = GSIMapNodeForKey(_remoteProxies, (GSIMapKey)target); + if (node != 0) + { + M_UNLOCK(_proxiesGate); + [NSException raise: NSGenericException + format: @"Trying to add the same proxy twice"]; + } + GSIMapAddPair(_remoteProxies, (GSIMapKey)target, (GSIMapVal)aProxy); + M_UNLOCK(_proxiesGate); +} + +- (id) includesProxyForTarget: (unsigned)target +{ + NSDistantObject *ret; + GSIMapNode node; + + /* Don't assert (_isValid); */ + M_LOCK(_proxiesGate); + node = GSIMapNodeForKey(_remoteProxies, (GSIMapKey)target); + if (node == 0) + { + ret = nil; + } + else + { + ret = node->value.obj; + } + M_UNLOCK(_proxiesGate); + return ret; +} + +- (id) includesLocalObject: (id)anObj +{ + NSDistantObject *ret; + GSIMapNode node; + + /* Don't assert (_isValid); */ + M_LOCK(_proxiesGate); + node = GSIMapNodeForKey(_localObjects, (GSIMapKey)anObj); + if (node == 0) + { + ret = nil; + } + else + { + ret = node->value.obj; + } + M_UNLOCK(_proxiesGate); + return ret; +} + +- (id) includesLocalTarget: (unsigned)target +{ + NSDistantObject *ret; + GSIMapNode node; + + /* Don't assert (_isValid); */ + M_LOCK(_proxiesGate); + node = GSIMapNodeForKey(_localTargets, (GSIMapKey)target); + if (node == 0) + { + ret = nil; + } + else + { + ret = node->value.obj; + } + M_UNLOCK(_proxiesGate); + return ret; +} + +/* Check all connections. + Proxy needs to use this when decoding a local object in order to + make sure the target address is a valid object. It is not enough + for the Proxy to check the Proxy's connection only (using + -includesLocalTarget), because the proxy may have come from a + triangle connection. */ ++ (id) includesLocalTarget: (unsigned)target +{ + id ret; + + /* Don't assert (_isValid); */ + M_LOCK(global_proxies_gate); + ret = NSMapGet(targetToCounter, (void*)target); + M_UNLOCK(global_proxies_gate); + return ret; +} + + +/* Accessing ivars */ + + +/* Prevent trying to encode the connection itself */ + +- (void) encodeWithCoder: (NSCoder*)anEncoder +{ + [self shouldNotImplement: _cmd]; +} + +- (id) initWithCoder: (NSCoder*)aDecoder; +{ + [self shouldNotImplement: _cmd]; + return self; +} + + +/* Shutting down and deallocating. */ + +/* + * We register this method for a notification when a port dies. + * NB. It is possible that the death of a port could be notified + * to us after we are invalidated - in which case we must ignore it. + */ +- (void) portIsInvalid: (NSNotification*)notification +{ + if (_isValid) + { + id port = [notification object]; + + if (debug_connection) + { + NSLog(@"Received port invalidation notification for " + @"connection 0x%x\n\t%@", (gsaddr)self, port); + } + + /* We shouldn't be getting any port invalidation notifications, + except from our own ports; this is how we registered ourselves + with the NSNotificationCenter in + +newForInPort: outPort: ancestorConnection. */ + NSParameterAssert (port == _receivePort || port == _sendPort); + + [self invalidate]; + } +} + +@end + +#else +/* Implementation of connection object for remote object messaging + Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc. + + Created by: Andrew Kachites McCallum + Date: July 1994 + Rewritten for OPENSTEP by: Richard Frith-Macdonald + Date: August 1997 + + 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. + */ + +/* To do: + Make it thread-safe. + */ + +/* RMC == Remote Method Coder, or Remote Method Call. + It's an instance of PortEncoder or PortDecoder. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +@interface NSDistantObject (NSConnection) +- (id) localForProxy; +- (void) setProxyTarget: (unsigned)target; +- (unsigned) targetForProxy; +@end + +@implementation NSDistantObject (NSConnection) +- (id) localForProxy +{ + return _object; +} +- (void) setProxyTarget: (unsigned)target +{ + _handle = target; +} +- (unsigned) targetForProxy +{ + return _handle; +} +@end + +/* + * GSLocalCounter is a trivial class to keep track of how + * many different connections a particular local object is vended + * over. This is required so that we know when to remove an object + * from the global list when it is removed from the list of objects + * vended on a particular connection. + */ +@interface GSLocalCounter : NSObject +{ +@public + unsigned ref; + unsigned target; + id object; +} ++ (GSLocalCounter*) newWithObject: (id)ob; +@end + +@implementation GSLocalCounter + +static unsigned local_object_counter = 0; + ++ (GSLocalCounter*) newWithObject: (id)obj +{ + GSLocalCounter *counter; + + counter = (GSLocalCounter*)NSAllocateObject(self, 0, NSDefaultMallocZone()); + counter->ref = 1; + counter->object = RETAIN(obj); + counter->target = ++local_object_counter; + return counter; +} +- (void) dealloc +{ + [object release]; + [super dealloc]; +} +@end + + + +/* + * CachedLocalObject is a trivial class to keep track of how + * many different connections a particular local object is vended + * over. This is required so that we know when to remove an object + * from the global list when it is removed from the list of objects + * vended on a particular connection. + */ +@interface CachedLocalObject : NSObject +{ + id obj; + int time; +} +- (BOOL)countdown; +- (id) obj; ++ (CachedLocalObject*) itemWithObject: (id)o time: (int)t; +@end + +@implementation CachedLocalObject + ++ (CachedLocalObject*) itemWithObject: (id)o time: (int)t +{ + CachedLocalObject *item = [[self alloc] init]; + + item->obj = RETAIN(o); + item->time = t; + return [item autorelease]; +} + +- (void) dealloc +{ + [obj release]; + [super dealloc]; +} + +- (BOOL) countdown +{ + if (time-- > 0) + return YES; + return NO; +} + +- (id) obj +{ + return obj; +} + +@end + + +@interface NSConnection (GettingCoderInterface) +- (void) _handleRmc: rmc; +- (void) _handleQueuedRmcRequests; +- _getReceivedReplyRmcWithSequenceNumber: (int)n; +- newSendingRequestRmc; +- newSendingReplyRmcWithSequenceNumber: (int)n; +- (int) _newMsgNumber; +@end + +@interface NSConnection (Private) +- _superInit; +- (void) handlePortMessage: (NSPortMessage*)msg; ++ (void) setDebug: (int)val; +@end + +#define proxiesHashGate refGate +#define sequenceNumberGate refGate + +/* xxx Fix this! */ +#define refGate nil + +static inline BOOL +class_is_kind_of (Class self, Class aClassObject) +{ + Class class; + + for (class = self; class!=Nil; class = class_get_super_class(class)) + if (class==aClassObject) + return YES; + return NO; +} + +static inline unsigned int +hash_int (cache_ptr cache, const void *key) +{ + return (unsigned)key & cache->mask; +} + +static inline int +compare_ints (const void *k1, const void *k2) +{ + return !(k1 - k2); +} + +/* class defaults */ +static id default_receive_port_class; +static id default_send_port_class; +static id default_proxy_class; +static id default_encoding_class; +static id default_decoding_class; +static int default_reply_timeout; +static int default_request_timeout; +static NSTimer *timer; + +static int debug_connection = 0; + +static NSHashTable *connection_table; +static NSLock *connection_table_gate; + +static NSMutableDictionary *root_object_dictionary; +static NSLock *root_object_dictionary_gate; + +static NSMapTable *receive_port_2_ancestor; + +static NSMapTable *all_connections_local_objects = NULL; +static NSMapTable *all_connections_local_targets = NULL; +static NSMapTable *all_connections_local_cached = NULL; + +/* rmc handling */ +static NSMutableArray *received_request_rmc_queue; +static NSLock *received_request_rmc_queue_gate; +static NSMutableArray *received_reply_rmc_queue; +static NSLock *received_reply_rmc_queue_gate; + +static int messages_received_count; + + + + +@implementation NSConnection + ++ (NSArray*) allConnections +{ + return NSAllHashTableObjects(connection_table); +} + ++ (NSConnection*) connectionWithRegisteredName: (NSString*)n + host: (NSString*)h +{ + NSDistantObject *proxy; + + proxy = [self rootProxyForConnectionWithRegisteredName: n host: h]; + if (proxy != nil) + { + return [proxy connectionForProxy]; + } + return nil; +} + +/* + * Get the default connection for a thread. + * Possible problem - if the connection is invalidated, it won't be + * cleaned up until this thread calls this method again. The connection + * and it's ports could hang around for a very long time. + */ ++ (NSConnection*) defaultConnection +{ + static NSString *tkey = @"NSConnectionThreadKey"; + NSConnection *c; + NSMutableDictionary *d; + + d = GSCurrentThreadDictionary(); + c = (NSConnection*)[d objectForKey: tkey]; + if (c != nil && [c isValid] == NO) + { + /* + * If the default connection for this thread has been invalidated - + * release it and create a new one. + */ + [d removeObjectForKey: tkey]; + c = nil; + } + if (c == nil) + { + NSPort *newPort; + + c = [self alloc]; + newPort = [default_receive_port_class newForReceiving]; + c = [c initWithReceivePort: newPort sendPort: nil]; + RELEASE(newPort); + [d setObject: c forKey: tkey]; + RELEASE(c); + } + return c; +} + ++ (void) initialize +{ + connection_table = + NSCreateHashTable(NSNonRetainedObjectHashCallBacks, 0); + connection_table_gate = [NSLock new]; + /* xxx When NSHashTable's are working, change this. */ + all_connections_local_objects = + NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks, + NSObjectMapValueCallBacks, 0); + all_connections_local_targets = + NSCreateMapTable(NSIntMapKeyCallBacks, + NSNonOwnedPointerMapValueCallBacks, 0); + all_connections_local_cached = + NSCreateMapTable(NSIntMapKeyCallBacks, + NSObjectMapValueCallBacks, 0); + received_request_rmc_queue = [[NSMutableArray alloc] initWithCapacity: 32]; + received_request_rmc_queue_gate = [NSLock new]; + received_reply_rmc_queue = [[NSMutableArray alloc] initWithCapacity: 32]; + received_reply_rmc_queue_gate = [NSLock new]; + root_object_dictionary = [[NSMutableDictionary alloc] initWithCapacity: 8]; + root_object_dictionary_gate = [NSLock new]; + receive_port_2_ancestor = + NSCreateMapTable (NSNonOwnedPointerMapKeyCallBacks, + NSNonOwnedPointerMapValueCallBacks, 0); + messages_received_count = 0; + default_receive_port_class = [TcpInPort class]; + default_send_port_class = [TcpOutPort class]; + default_proxy_class = [NSDistantObject class]; + default_encoding_class = [NSPortCoder class]; + default_decoding_class = [NSPortCoder class]; + default_reply_timeout = CONNECTION_DEFAULT_TIMEOUT; + default_request_timeout = CONNECTION_DEFAULT_TIMEOUT; +} + ++ (id) new +{ + /* + * Undocumented feature of OPENSTEP/MacOS-X + * +new returns the default connection. + */ + return RETAIN([self defaultConnection]); +} + ++ (id) currentConversation +{ + [self notImplemented: _cmd]; + return self; +} + ++ (NSDistantObject*) rootProxyForConnectionWithRegisteredName: (NSString*)n + host: (NSString*)h +{ + id p = [default_send_port_class newForSendingToRegisteredName: n onHost: h]; + if (p == nil) + { + return nil; + } + return [self rootProxyAtPort: [p autorelease]]; +} + ++ (void) _timeout: (NSTimer*)t +{ + NSArray *cached_locals; + int i; + + cached_locals = NSAllMapTableValues(all_connections_local_cached); + for (i = [cached_locals count]; i > 0; i--) + { + CachedLocalObject *item = [cached_locals objectAtIndex: i-1]; + + if ([item countdown] == NO) + { + GSLocalCounter *counter = [item obj]; + NSMapRemove(all_connections_local_cached, (void*)counter->target); + } + } + if ([cached_locals count] == 0) + { + [t invalidate]; + timer = nil; + } +} + +- (void) addRequestMode: (NSString*)mode +{ + if ([request_modes containsObject: mode] == NO) + { + [request_modes addObject: mode]; + [[NSRunLoop currentRunLoop] addPort: receive_port forMode: mode]; + } +} + +- (void) addRunLoop: (NSRunLoop*)loop +{ + [self notImplemented: _cmd]; +} + +- (void) dealloc +{ + if (debug_connection) + NSLog(@"deallocating 0x%x\n", (gsaddr)self); + [super dealloc]; +} + +- (id) delegate +{ + return delegate; +} + +- (void) handlePortMessage: (NSPortMessage*)msg +{ + [self notImplemented: _cmd]; +} + +- (BOOL) independentConversationQueueing +{ + return independent_queueing; +} + +- (void) enableMultipleThreads +{ + [self notImplemented: _cmd]; +} + +- (BOOL) multipleThreadsEnabled +{ + [self notImplemented: _cmd]; + return NO; +} + + +- (id) init +{ + /* + * Undocumented feature of OPENSTEP/MacOS-X + * -init returns the default connection. + */ + RELEASE(self); + return [NSConnection defaultConnection]; +} + +/* xxx This needs locks */ +- (void) invalidate +{ + if (is_valid == NO) + return; + + is_valid = NO; + + NSHashRemove(connection_table, self); + + /* + * Don't need notifications any more - so remove self as observer. + */ + [[NSNotificationCenter defaultCenter] removeObserver: self]; + + /* + * We can't be the ancestor of anything if we are invalid. + */ + if (self == NSMapGet(receive_port_2_ancestor, receive_port)) + NSMapRemove(receive_port_2_ancestor, receive_port); + + /* + * If we have been invalidated, we don't need to retain proxies + * for local objects any more. In fact, we want to get rid of + * these proxies in case they are keeping us retained when we + * might otherwise de deallocated. + */ + { + NSArray *targets; + unsigned i; + + [proxiesHashGate lock]; + targets = NSAllMapTableValues(local_targets); + IF_NO_GC(RETAIN(targets)); + for (i = 0; i < [targets count]; i++) + { + id t = [[targets objectAtIndex: i] localForProxy]; + + [self removeLocalObject: t]; + } + [targets release]; + [proxiesHashGate unlock]; + } + + if (debug_connection) + NSLog(@"Invalidating connection 0x%x\n\t%@\n\t%@\n", (gsaddr)self, + [receive_port description], [send_port description]); + + /* + * We need to notify any watchers of our death - but if we are already + * in the deallocation process, we can't have a notification retaining + * and autoreleasing us later once we are deallocated - so we do the + * notification with a local autorelease pool to ensure that any release + * is done before the deallocation completes. + */ + { + CREATE_AUTORELEASE_POOL(arp); + + [[NSNotificationCenter defaultCenter] + postNotificationName: NSConnectionDidDieNotification + object: self]; + RELEASE(arp); + } +} + +- (BOOL) isValid +{ + return is_valid; +} + +- (BOOL) registerName: (NSString*)name +{ + NSPortNameServer *svr = [NSPortNameServer systemDefaultPortNameServer]; + NSArray *names = [svr namesForPort: receive_port]; + BOOL result = YES; + + if (name != nil) + { + result = [svr registerPort: receive_port forName: name]; + } + if (result == YES && [names count] > 0) + { + unsigned i; + + for (i = 0; i < [names count]; i++) + { + NSString *tmp = [names objectAtIndex: i]; + + if ([tmp isEqualToString: name] == NO) + { + [svr removePort: receive_port forName: name]; + } + } + } + return result; +} + +- (void) release +{ + /* + * If this would cause the connection to be deallocated then we + * must perform all necessary work (done in [-gcFinalize]). + * We bracket the code with a retain and release so that any + * retain/release pairs in the code won't cause recursion. + */ + if ([self retainCount] == 1) + { + [super retain]; + [self gcFinalize]; + [super release]; + } + [super release]; +} + +- (NSArray *) remoteObjects +{ + [self notImplemented: _cmd]; + return nil; +} + +- (void) removeRequestMode: (NSString*)mode +{ + if ([request_modes containsObject: mode]) + { + [request_modes removeObject: mode]; + [[NSRunLoop currentRunLoop] removePort: receive_port forMode: mode]; + } +} + +- (void) removeRunLoop: (NSRunLoop *)runloop +{ + [self notImplemented: _cmd]; +} + +- (NSTimeInterval) replyTimeout +{ + return reply_timeout; +} + +- (NSArray*) requestModes +{ + return [[request_modes copy] autorelease]; +} + +- (NSTimeInterval) requestTimeout +{ + return request_timeout; +} + +- (id) rootObject +{ + return [[self class] rootObjectForInPort: receive_port]; +} + +- (NSDistantObject*) rootProxy +{ + id op, ip; + NSDistantObject *newProxy = nil; + int seq_num = [self _newMsgNumber]; + + NSParameterAssert(receive_port); + NSParameterAssert (is_valid); + op = [[self encodingClass] + newForWritingWithConnection: self + sequenceNumber: seq_num + identifier: ROOTPROXY_REQUEST]; + [op dismiss]; + ip = [self _getReceivedReplyRmcWithSequenceNumber: seq_num]; + [ip decodeObjectAt: &newProxy withName: NULL]; + NSParameterAssert (class_is_kind_of (newProxy->isa, objc_get_class ("NSDistantObject"))); + [ip dismiss]; + return [newProxy autorelease]; +} + +- (void) setDelegate: anObj +{ + delegate = anObj; +} + +- (void) setIndependentConversationQueueing: (BOOL)flag +{ + independent_queueing = flag; +} + +- (void) setReplyTimeout: (NSTimeInterval)to +{ + reply_timeout = to; +} + +- (void) setRequestMode: (NSString*)mode +{ + while ([request_modes count] > 0 && [request_modes objectAtIndex: 0] != mode) + { + [self removeRequestMode: [request_modes objectAtIndex: 0]]; + } + while ([request_modes count] > 1) + { + [self removeRequestMode: [request_modes objectAtIndex: 1]]; + } + if (mode != nil && [request_modes count] == 0) + { + [self addRequestMode: mode]; + } +} + +- (void) setRequestTimeout: (NSTimeInterval)to +{ + request_timeout = to; +} + +- (void) setRootObject: anObj +{ + [[self class] setRootObject: anObj forInPort: receive_port]; +} + +- (NSDictionary*) statistics +{ + NSMutableDictionary *d; + id o; + + d = [NSMutableDictionary dictionaryWithCapacity: 8]; + + /* + * These are in OPENSTEP 4.2 + */ + o = [NSNumber numberWithUnsignedInt: rep_in_count]; + [d setObject: o forKey: NSConnectionRepliesReceived]; + o = [NSNumber numberWithUnsignedInt: rep_out_count]; + [d setObject: o forKey: NSConnectionRepliesSent]; + o = [NSNumber numberWithUnsignedInt: req_in_count]; + [d setObject: o forKey: NSConnectionRequestsReceived]; + o = [NSNumber numberWithUnsignedInt: req_out_count]; + [d setObject: o forKey: NSConnectionRequestsSent]; + + /* + * These are GNUstep extras + */ + o = [NSNumber numberWithUnsignedInt: NSCountMapTable(local_targets)]; + [d setObject: o forKey: NSConnectionLocalCount]; + o = [NSNumber numberWithUnsignedInt: NSCountMapTable(remote_proxies)]; + [d setObject: o forKey: NSConnectionProxyCount]; + [received_request_rmc_queue_gate lock]; + o = [NSNumber numberWithUnsignedInt: [received_request_rmc_queue count]]; + [received_request_rmc_queue_gate unlock]; + [d setObject: o forKey: @"Pending packets"]; + + return d; +} + +@end + + + +@implementation NSConnection (GNUstepExtensions) + +- (void) gcFinalize +{ + CREATE_AUTORELEASE_POOL(arp); + + if (debug_connection) + NSLog(@"finalising 0x%x\n", (gsaddr)self); + + [self invalidate]; + + /* Remove rootObject from root_object_dictionary + if this is last connection */ + if (receive_port != nil + && [NSConnection connectionsCountWithInPort: receive_port] == 0) + { + [NSConnection setRootObject: nil forInPort: receive_port]; + } + + /* Remove receive port from run loop. */ + [self setRequestMode: nil]; + if (receive_port != nil) + { + [[NSRunLoop currentRunLoop] removePort: receive_port + forMode: NSConnectionReplyMode]; + } + RELEASE(request_modes); + + /* Finished with ports - releasing them may generate a notification */ + RELEASE(receive_port); + RELEASE(send_port); + + [proxiesHashGate lock]; + if (remote_proxies != 0) + NSFreeMapTable(remote_proxies); + if (local_objects != 0) + NSFreeMapTable(local_objects); + if (local_targets != 0) + NSFreeMapTable(local_targets); + [proxiesHashGate unlock]; + + RELEASE(arp); +} + +/* Getting and setting class variables */ + ++ (Class) default_decoding_class +{ + return default_decoding_class; +} + ++ (int) defaultInTimeout +{ + return default_reply_timeout; +} + ++ (int) defaultOutTimeout +{ + return default_request_timeout; +} + ++ (Class) defaultProxyClass +{ + return default_proxy_class; +} + ++ (Class) defaultReceivePortClass +{ + return default_receive_port_class; +} + ++ (Class) defaultSendPortClass +{ + return default_send_port_class; +} + ++ (void) setDefaultDecodingClass: (Class) aClass +{ + default_decoding_class = aClass; +} + ++ (void) setDefaultInTimeout: (int)to +{ + default_reply_timeout = to; +} + ++ (void) setDefaultOutTimeout: (int)to +{ + default_request_timeout = to; +} + ++ (void) setDefaultProxyClass: (Class)aClass +{ + default_proxy_class = aClass; +} + ++ (void) setDefaultReceivePortClass: (Class)aClass +{ + default_receive_port_class = aClass; +} + ++ (void) setDefaultSendPortClass: (Class)aClass +{ + default_send_port_class = aClass; +} + +/* Class-wide stats and collections. */ + ++ (int) messagesReceived +{ + return messages_received_count; +} + ++ (unsigned) connectionsCount +{ + return NSCountHashTable(connection_table); +} + ++ (unsigned) connectionsCountWithInPort: (NSPort*)aPort +{ + unsigned count = 0; + NSHashEnumerator enumerator; + NSConnection *o; + + [connection_table_gate lock]; + enumerator = NSEnumerateHashTable(connection_table); + while ((o = (NSConnection*)NSNextHashEnumeratorItem(&enumerator)) != nil) + { + if ([aPort isEqual: [o receivePort]]) + { + count++; + } + } + [connection_table_gate unlock]; + + return count; +} + + +/* Creating and initializing connections. */ + ++ (NSConnection*) newWithRootObject: anObj; +{ + id newPort; + id newConn; + + newPort = [[default_receive_port_class newForReceiving] autorelease]; + newConn = [self newForInPort: newPort outPort: nil + ancestorConnection: nil]; + [[self class] setRootObject: anObj forInPort: newPort]; + return newConn; +} + +/* I want this method name to clearly indicate that we're not connecting + to a pre-existing registration name, we're registering a new name, + and this method will fail if that name has already been registered. + This is why I don't like "newWithRegisteredName: " --- it's unclear + if we're connecting to another NSConnection that already registered + with that name. */ + ++ (NSConnection*) newRegisteringAtName: (NSString*)n withRootObject: anObj +{ + return [self newRegisteringAtName: n + atPort: 0 + withRootObject: anObj]; +} + ++ (NSConnection*) newRegisteringAtName: (NSString*)n + atPort: (int)p + withRootObject: anObj +{ + id newPort; + id newConn; + + newPort = [default_receive_port_class newForReceiving]; + newConn = [self alloc]; + newConn = [newConn initWithReceivePort: newPort sendPort: nil]; + RELEASE(newPort); + [newConn setRootObject: anObj]; + if ([newConn registerName: n] == NO) + { + DESTROY(newConn); + } + return newConn; +} + ++ (NSDistantObject*) rootProxyAtName: (NSString*)n +{ + return [self rootProxyAtName: n onHost: @""]; +} + ++ (NSDistantObject*) rootProxyAtName: (NSString*)n onHost: (NSString*)h +{ + return [self rootProxyForConnectionWithRegisteredName: n host: h]; +} + ++ (NSDistantObject*) rootProxyAtPort: (NSPort*)anOutPort +{ + NSConnection *c = [self connectionByOutPort: anOutPort]; + + if (c) + return [c rootProxy]; + else + { + id newInPort = [default_receive_port_class newForReceiving]; + return [self rootProxyAtPort: anOutPort + withInPort: [newInPort autorelease]]; + } +} + ++ (NSDistantObject*) rootProxyAtPort: (NSPort*)anOutPort + withInPort: (NSPort *)anInPort +{ + NSConnection *newConn = [self newForInPort: anInPort + outPort: anOutPort + ancestorConnection: nil]; + NSDistantObject *newRemote; + + newRemote = [newConn rootProxy]; + [newConn autorelease]; + return newRemote; +} + + ++ (NSConnection*) newForInPort: (NSPort*)ip + outPort: (NSPort*)op + ancestorConnection: (NSConnection*)ancestor +{ + NSConnection *conn; + + conn = [self alloc]; + conn = [conn initWithReceivePort: ip sendPort: op]; + return conn; +} + ++ (NSConnection*) connectionByInPort: (NSPort*)ip + outPort: (NSPort*)op +{ + NSHashEnumerator enumerator; + NSConnection *o; + + NSParameterAssert (ip); + + [connection_table_gate lock]; + + enumerator = NSEnumerateHashTable(connection_table); + while ((o = (NSConnection*)NSNextHashEnumeratorItem(&enumerator)) != nil) + { + id newConnInPort; + id newConnOutPort; + + newConnInPort = [o receivePort]; + newConnOutPort = [o sendPort]; + if ([newConnInPort isEqual: ip] + && [newConnOutPort isEqual: op]) + { + [connection_table_gate unlock]; + return o; + } + } + [connection_table_gate unlock]; + return nil; +} + ++ (NSConnection*) connectionByOutPort: (NSPort*)op +{ + NSHashEnumerator enumerator; + NSConnection *o; + + NSParameterAssert (op); + + [connection_table_gate lock]; + + enumerator = NSEnumerateHashTable(connection_table); + while ((o = (NSConnection*)NSNextHashEnumeratorItem(&enumerator)) != nil) + { + id newConnOutPort; + + newConnOutPort = [o sendPort]; + if ([newConnOutPort isEqual: op]) + { + [connection_table_gate unlock]; + return o; + } + } + [connection_table_gate unlock]; + return nil; +} + +- _superInit +{ + [super init]; + return self; +} + ++ (void) setDebug: (int)val +{ + debug_connection = val; +} + +/* Creating new rmc's for encoding requests and replies */ + +/* Create a new, empty rmc, which will be filled with a request. */ +- newSendingRequestRmc +{ + id rmc; + + NSParameterAssert(receive_port); + NSParameterAssert (is_valid); + rmc = [[self encodingClass] newForWritingWithConnection: self + sequenceNumber: [self _newMsgNumber] + identifier: METHOD_REQUEST]; + return rmc; +} + +/* Create a new, empty rmc, which will be filled with a reply to msg #n. */ +- newSendingReplyRmcWithSequenceNumber: (int)n +{ + id rmc = [[self encodingClass] newForWritingWithConnection: self + sequenceNumber: n + identifier: METHOD_REPLY]; + NSParameterAssert (is_valid); + return rmc; +} + + +/* Methods for handling client and server, requests and replies */ + +/* NSDistantObject's -forward: : method calls this to the the message over the wire. */ +- (retval_t) forwardForProxy: (NSDistantObject*)object + selector: (SEL)sel + argFrame: (arglist_t)argframe +{ + NSPortCoder *op; + + /* The callback for encoding the args of the method call. */ + void encoder (int argnum, void *datum, const char *type, int flags) + { +#define ENCODED_ARGNAME @"argument value" + switch (*type) + { + case _C_ID: + if (flags & _F_BYCOPY) + [op encodeBycopyObject: *(id*)datum withName: ENCODED_ARGNAME]; +#ifdef _F_BYREF + else if (flags & _F_BYREF) + [op encodeByrefObject: *(id*)datum withName: ENCODED_ARGNAME]; +#endif + else + [op encodeObject: *(id*)datum withName: ENCODED_ARGNAME]; + break; + default: + [op encodeValueOfObjCType: type at: datum withName: ENCODED_ARGNAME]; + } + } + + /* Encode the method on an RMC, and send it. */ + { + BOOL out_parameters; + const char *type; + retval_t retframe; + int seq_num; + + NSParameterAssert (is_valid); + + /* get the method types from the selector */ +#if NeXT_runtime + [NSException + raise: NSGenericException + format: @"Sorry, distributed objects does not work with NeXT runtime"]; + /* type = [object selectorTypeForProxy: sel]; */ +#else + type = sel_get_type(sel); +#endif + if (type == 0 || *type == '\0') { + type = [[object methodSignatureForSelector: sel] methodType]; + if (type) { + sel_register_typed_name(sel_get_name(sel), type); + } + } + NSParameterAssert(type); + NSParameterAssert(*type); + + op = [self newSendingRequestRmc]; + seq_num = [op sequenceNumber]; + if (debug_connection > 4) + NSLog(@"building packet seq %d\n", seq_num); + + /* Send the types that we're using, so that the performer knows + exactly what qualifiers we're using. + If all selectors included qualifiers, and if I could make + sel_types_match() work the way I wanted, we wouldn't need to do + this. */ + [op encodeValueOfCType: @encode(char*) + at: &type + withName: @"selector type"]; + + /* xxx This doesn't work with proxies and the NeXT runtime because + type may be a method_type from a remote machine with a + different architecture, and its argframe layout specifiers + won't be right for this machine! */ + out_parameters = mframe_dissect_call (argframe, type, encoder); + /* Send the rmc */ + [op dismiss]; + if (debug_connection > 1) + NSLog(@"Sent message to 0x%x\n", (gsaddr)self); + req_out_count++; /* Sent a request. */ + + /* Get the reply rmc, and decode it. */ + { + NSPortCoder *ip = nil; + BOOL is_exception = NO; + + void decoder(int argnum, void *datum, const char *type, int flags) + { + if (type == 0) { + if (ip) { + /* this must be here to avoid trashing alloca'ed retframe */ + [ip dismiss]; + ip = (id)-1; + } + return; + } + /* If we didn't get the reply packet yet, get it now. */ + if (!ip) + { + if (!is_valid) + { + [NSException raise: NSGenericException + format: @"connection waiting for request was shut down"]; + } + /* xxx Why do we get the reply packet in here, and not + just before calling dissect_method_return() below? */ + ip = [self _getReceivedReplyRmcWithSequenceNumber: seq_num]; + /* Find out if the server is returning an exception instead + of the return values. */ + [ip decodeValueOfCType: @encode(BOOL) + at: &is_exception + withName: NULL]; + if (is_exception) + { + /* Decode the exception object, and raise it. */ + id exc; + [ip decodeObjectAt: &exc + withName: NULL]; + [ip dismiss]; + ip = (id)-1; + /* xxx Is there anything else to clean up in + dissect_method_return()? */ + [exc raise]; + } + } + [ip decodeValueOfObjCType: type at: datum withName: NULL]; + /* -decodeValueOfCType: at: withName: malloc's new memory + for char*'s. We need to make sure it gets freed eventually + so we don't have a memory leak. Request here that it be + autorelease'ed. Also autorelease created objects. */ + if (*type == _C_CHARPTR) + [NSData dataWithBytesNoCopy: *(void**)datum length: 1]; + else if (*type == _C_ID) + [*(id*)datum autorelease]; + } + + retframe = mframe_build_return (argframe, type, out_parameters, + decoder); + /* Make sure we processed all arguments, and dismissed the IP. + IP is always set to -1 after being dismissed; the only places + this is done is in this function DECODER(). IP will be nil + if mframe_build_return() never called DECODER(), i.e. when + we are just returning (void).*/ + NSAssert(ip == (id)-1 || ip == nil, NSInternalInconsistencyException); + rep_in_count++; /* received a reply */ + return retframe; + } + } +} + +/* NSConnection calls this to service the incoming method request. */ +- (void) _service_forwardForProxy: aRmc +{ + char *forward_type = 0; + id op = nil; + int reply_sequence_number; + + void decoder (int argnum, void *datum, const char *type) + { + /* We need this "dismiss" to happen here and not later so that Coder + "-awake..." methods will get sent before the __builtin_apply! */ + if (argnum == -1 && datum == 0 && type == 0) + { + [aRmc dismiss]; + return; + } + + [aRmc decodeValueOfObjCType: type + at: datum + withName: NULL]; + /* -decodeValueOfCType: at: withName: malloc's new memory + for char*'s. We need to make sure it gets freed eventually + so we don't have a memory leak. Request here that it be + autorelease'ed. Also autorelease created objects. */ + if (*type == _C_CHARPTR) + [NSData dataWithBytesNoCopy: *(void**)datum length: 1]; + else if (*type == _C_ID) + [*(id*)datum autorelease]; + } + + void encoder (int argnum, void *datum, const char *type, int flags) + { +#define ENCODED_RETNAME @"return value" + if (op == nil) + { + BOOL is_exception = NO; + /* It is possible that our connection died while the method was + being called - in this case we mustn't try to send the result + back to the remote application! */ + if (!is_valid) + return; + op = [self newSendingReplyRmcWithSequenceNumber: + reply_sequence_number]; + [op encodeValueOfCType: @encode(BOOL) + at: &is_exception + withName: @"Exceptional reply flag"]; + } + switch (*type) + { + case _C_ID: + if (flags & _F_BYCOPY) + [op encodeBycopyObject: *(id*)datum withName: ENCODED_RETNAME]; +#ifdef _F_BYREF + else if (flags & _F_BYREF) + [op encodeByrefObject: *(id*)datum withName: ENCODED_ARGNAME]; +#endif + else + [op encodeObject: *(id*)datum withName: ENCODED_RETNAME]; + break; + default: + [op encodeValueOfObjCType: type at: datum withName: ENCODED_RETNAME]; + } + } + + /* Make sure don't let exceptions caused by servicing the client's + request cause us to crash. */ + NS_DURING + { + NSParameterAssert (is_valid); + + /* Save this for later */ + reply_sequence_number = [aRmc sequenceNumber]; + + /* Get the types that we're using, so that we know + exactly what qualifiers the forwarder used. + If all selectors included qualifiers and I could make + sel_types_match() work the way I wanted, we wouldn't need + to do this. */ + [aRmc decodeValueOfCType: @encode(char*) + at: &forward_type + withName: NULL]; + + if (debug_connection > 1) + NSLog(@"Handling message from 0x%x\n", (gsaddr)self); + req_in_count++; /* Handling an incoming request. */ + mframe_do_call (forward_type, decoder, encoder); + [op dismiss]; + rep_out_count++; /* Sent back a reply. */ + } + + /* Make sure we pass all exceptions back to the requestor. */ + NS_HANDLER + { + BOOL is_exception = YES; + + /* Try to clean up a little. */ + DESTROY(op); + + /* Send the exception back to the client. */ + if (is_valid) + { + NS_DURING + { + op = [self newSendingReplyRmcWithSequenceNumber: + reply_sequence_number]; + [op encodeValueOfCType: @encode(BOOL) + at: &is_exception + withName: @"Exceptional reply flag"]; + [op encodeBycopyObject: localException + withName: @"Exception object"]; + [op dismiss]; + } + NS_HANDLER + { + DESTROY(op); + NSLog(@"Exception when sending exception back to client - %@", + localException); + } + NS_ENDHANDLER; + } + } + NS_ENDHANDLER; + + if (forward_type) + objc_free (forward_type); +} + +- (void) _service_rootObject: rmc +{ + id rootObject = [NSConnection rootObjectForInPort: receive_port]; + NSPortCoder* op = [[self encodingClass] + newForWritingWithConnection: [rmc connection] + sequenceNumber: [rmc sequenceNumber] + identifier: ROOTPROXY_REPLY]; + NSParameterAssert (receive_port); + NSParameterAssert (is_valid); + /* Perhaps we should turn this into a class method. */ + NSParameterAssert([rmc connection] == self); + [op encodeObject: rootObject withName: @"root object"]; + [op dismiss]; + [rmc dismiss]; +} + +- (void) _service_release: rmc forConnection: receiving_connection +{ + unsigned int count; + unsigned int pos; + + NSParameterAssert (is_valid); + + if ([rmc connection] != self) + { + [rmc dismiss]; + [NSException raise: @"ProxyDecodedBadTarget" + format: @"request to release object on bad connection"]; + } + + [rmc decodeValueOfCType: @encode(typeof(count)) + at: &count + withName: NULL]; + + for (pos = 0; pos < count; pos++) + { + unsigned target; + NSDistantObject *prox; + + [rmc decodeValueOfCType: @encode(typeof(target)) + at: &target + withName: NULL]; + + prox = (NSDistantObject*)[self includesLocalTarget: target]; + if (prox != nil) + { + if (debug_connection > 3) + NSLog(@"releasing object with target (0x%x) on (0x%x)", + target, (gsaddr)self); + [self removeLocalObject: [prox localForProxy]]; + } + else if (debug_connection > 3) + NSLog(@"releasing object with target (0x%x) on (0x%x) - nothing to do", + target, (gsaddr)self); + } + + [rmc dismiss]; +} + +- (void) _service_retain: rmc forConnection: receiving_connection +{ + unsigned target; + NSPortCoder *op; + + NSParameterAssert (is_valid); + + if ([rmc connection] != self) + { + [rmc dismiss]; + [NSException raise: @"ProxyDecodedBadTarget" + format: @"request to retain object on bad connection"]; + } + + op = [[self encodingClass] newForWritingWithConnection: [rmc connection] + sequenceNumber: [rmc sequenceNumber] + identifier: RETAIN_REPLY]; + + [rmc decodeValueOfCType: @encode(typeof(target)) + at: &target + withName: NULL]; + + if (debug_connection > 3) + NSLog(@"looking to retain local object with target (0x%x) on (0x%x)", + target, (gsaddr)self); + + if ([self includesLocalTarget: target] == nil) + { + GSLocalCounter *counter; + + [proxiesHashGate lock]; + counter = NSMapGet (all_connections_local_targets, (void*)target); + if (counter == nil) + { + /* + * If the target doesn't exist for any connection, but still + * persists in the cache (ie it was recently released) then + * we move it back from the cache to the main maps so we can + * retain it on this connection. + */ + counter = NSMapGet (all_connections_local_cached, (void*)target); + if (counter) + { + unsigned t = counter->target; + id o = counter->object; + + NSMapInsert(all_connections_local_objects, (void*)o, counter); + NSMapInsert(all_connections_local_targets, (void*)t, counter); + NSMapRemove(all_connections_local_cached, (void*)t); + if (debug_connection > 3) + NSLog(@"target (0x%x) moved from cache", target); + } + } + [proxiesHashGate unlock]; + if (counter == nil) + { + [op encodeObject: @"target not found anywhere" + withName: @"retain failed"]; + if (debug_connection > 3) + NSLog(@"target (0x%x) not found anywhere for retain", target); + } + else + { + [NSDistantObject proxyWithLocal: counter->object + connection: self]; + [op encodeObject: nil withName: @"retain ok"]; + if (debug_connection > 3) + NSLog(@"retained object (0x%x) target (0x%x) on connection(0x%x)", + counter->object, counter->target, self); + } + } + else + { + [op encodeObject: nil withName: @"already retained"]; + if (debug_connection > 3) + NSLog(@"target (0x%x) already retained on connection (0x%x)", + target, self); + } + + [op dismiss]; + [rmc dismiss]; +} + +- (void) shutdown +{ + id op; + + NSParameterAssert(receive_port); + NSParameterAssert (is_valid); + op = [[self encodingClass] + newForWritingWithConnection: self + sequenceNumber: [self _newMsgNumber] + identifier: CONNECTION_SHUTDOWN]; + [op dismiss]; +} + +- (void) _service_shutdown: rmc forConnection: receiving_connection +{ + NSParameterAssert (is_valid); + [self invalidate]; + if (receiving_connection == self) + [NSException raise: NSGenericException + format: @"connection waiting for request was shut down"]; + [rmc dismiss]; +} + +- (const char *) typeForSelector: (SEL)sel remoteTarget: (unsigned)target +{ + id op, ip; + char *type = 0; + int seq_num; + + NSParameterAssert(receive_port); + NSParameterAssert (is_valid); + seq_num = [self _newMsgNumber]; + op = [[self encodingClass] + newForWritingWithConnection: self + sequenceNumber: seq_num + identifier: METHODTYPE_REQUEST]; + [op encodeValueOfObjCType: ": " + at: &sel + withName: NULL]; + [op encodeValueOfCType: @encode(unsigned) + at: &target + withName: NULL]; + [op dismiss]; + ip = [self _getReceivedReplyRmcWithSequenceNumber: seq_num]; + [ip decodeValueOfCType: @encode(char*) + at: &type + withName: NULL]; + [ip dismiss]; + return type; +} + +- (void) _service_typeForSelector: rmc +{ + NSPortCoder* op; + unsigned target; + NSDistantObject *p; + id o; + SEL sel; + const char *type; + struct objc_method* m; + + NSParameterAssert(receive_port); + NSParameterAssert (is_valid); + NSParameterAssert([rmc connection] == self); + op = [[self encodingClass] + newForWritingWithConnection: [rmc connection] + sequenceNumber: [rmc sequenceNumber] + identifier: METHODTYPE_REPLY]; + + [rmc decodeValueOfObjCType: ": " + at: &sel + withName: NULL]; + [rmc decodeValueOfCType: @encode(unsigned) + at: &target + withName: NULL]; + p = [self includesLocalTarget: target]; + o = [p localForProxy]; + + /* xxx We should make sure that TARGET is a valid object. */ + /* Not actually a Proxy, but we avoid the warnings "id" would have made. */ + m = class_get_instance_method(((NSDistantObject*)o)->isa, sel); + /* Perhaps I need to be more careful in the line above to get the + version of the method types that has the type qualifiers in it. + Search the protocols list. */ + if (m) + type = m->method_types; + else + type = ""; + [op encodeValueOfCType: @encode(char*) + at: &type + withName: @"Requested Method Type for Target"]; + [op dismiss]; + [rmc dismiss]; +} + + +/* Running the connection, getting/sending requests/replies. */ + +- (void) runConnectionUntilDate: date +{ + [NSRunLoop runUntilDate: date]; +} + +- (void) runConnection +{ + [self runConnectionUntilDate: [NSDate distantFuture]]; +} + +- (void) _handleRmc: rmc +{ + NSConnection *conn = [rmc connection]; + int ident = [rmc identifier]; + + if (debug_connection > 4) + NSLog(@"handling packet of type %d seq %d\n", ident, [rmc sequenceNumber]); + + switch (ident) + { + case ROOTPROXY_REQUEST: + /* It won't take much time to handle this, so go ahead and service + it, even if we are waiting for a reply. */ + [conn _service_rootObject: rmc]; + break; + case METHODTYPE_REQUEST: + /* It won't take much time to handle this, so go ahead and service + it, even if we are waiting for a reply. */ + [conn _service_typeForSelector: rmc]; + break; + case METHOD_REQUEST: + /* We just got a new request; we need to decide whether to queue + it or service it now. + If the REPLY_DEPTH is 0, then we aren't in the middle of waiting + for a reply, we are waiting for requests---so service it now. + If REPLY_DEPTH is non-zero, we may still want to service it now + if independent_queuing is NO. */ + if (request_depth == 0 || independent_queueing == NO) + { + request_depth++; + [conn _service_forwardForProxy: rmc]; + request_depth--; + /* Service any requests that were queued while we + were waiting for replies. + xxx Is this the right place for this check? */ + if (request_depth == 0) + [self _handleQueuedRmcRequests]; + } + else + { + [received_request_rmc_queue_gate lock]; + [received_request_rmc_queue addObject: rmc]; + [received_request_rmc_queue_gate unlock]; + } + break; + case ROOTPROXY_REPLY: + case METHOD_REPLY: + case METHODTYPE_REPLY: + case RETAIN_REPLY: + /* Remember multi-threaded callbacks will have to be handled specially */ + [received_reply_rmc_queue_gate lock]; + [received_reply_rmc_queue addObject: rmc]; + [received_reply_rmc_queue_gate unlock]; + break; + case CONNECTION_SHUTDOWN: + { + [conn _service_shutdown: rmc forConnection: self]; + break; + } + case PROXY_RELEASE: + { + [conn _service_release: rmc forConnection: self]; + break; + } + case PROXY_RETAIN: + { + [conn _service_retain: rmc forConnection: self]; + break; + } + default: + [rmc dismiss]; + [NSException raise: NSGenericException + format: @"unrecognized NSPortCoder identifier"]; + } +} + +- (void) _handleQueuedRmcRequests +{ + id rmc; + + [received_request_rmc_queue_gate lock]; + RETAIN(self); + while (is_valid && ([received_request_rmc_queue count] > 0)) + { + rmc = [received_request_rmc_queue objectAtIndex: 0]; + RETAIN(rmc); + [received_request_rmc_queue removeObjectAtIndex: 0]; + [received_request_rmc_queue_gate unlock]; + [self _handleRmc: rmc]; + [received_request_rmc_queue_gate lock]; + RELEASE(rmc); + } + RELEASE(self); + [received_request_rmc_queue_gate unlock]; +} + +/* Deal with an RMC, either by queuing it for later service, or + by servicing it right away. This method is called by the + receive_port's received-packet-invocation. */ + +/* Look for it on the queue, if it is not there, return nil. */ +- _getReceivedReplyRmcFromQueueWithSequenceNumber: (int)sn +{ + id the_rmc = nil; + unsigned count, i; + + [received_reply_rmc_queue_gate lock]; + + count = [received_reply_rmc_queue count]; + /* xxx There should be a per-thread queue of rmcs so we can do + callbacks when multi-threaded. */ + for (i = 0; i < count; i++) + { + id a_rmc = [received_reply_rmc_queue objectAtIndex: i]; + if ([a_rmc connection] == self + && [a_rmc sequenceNumber] == sn) + { + if (debug_connection) + NSLog(@"Getting received reply from queue\n"); + [received_reply_rmc_queue removeObjectAtIndex: i]; + the_rmc = a_rmc; + break; + } + /* xxx Make sure that there isn't a higher sequenceNumber, meaning + that we somehow dropped a packet. */ + } + [received_reply_rmc_queue_gate unlock]; + return the_rmc; +} + +/* Check the queue, then try to get it from the network by waiting + while we run the NSRunLoop. Raise exception if we don't get anything + before timing out. */ +- _getReceivedReplyRmcWithSequenceNumber: (int)sn +{ + id rmc; + id timeout_date = nil; + + while (!(rmc = [self _getReceivedReplyRmcFromQueueWithSequenceNumber: sn])) + { + if (!timeout_date) + timeout_date = [[NSDate alloc] + initWithTimeIntervalSinceNow: reply_timeout]; + if ([NSRunLoop runOnceBeforeDate: timeout_date + forMode: NSConnectionReplyMode] == NO) + break; + } + if (timeout_date) + [timeout_date release]; + if (rmc == nil) + [NSException raise: NSPortTimeoutException + format: @"timed out waiting for reply"]; + return rmc; +} + +/* Sneaky, sneaky. See "sneaky" comment in TcpPort.m. + This method is called by InPort when it receives a new packet. */ ++ (void) invokeWithObject: packet +{ + id rmc; + NSConnection *connection; + + if (debug_connection > 3) + NSLog(@"packet arrived on %@", [[packet receivingInPort] description]); + + connection = NSMapGet(receive_port_2_ancestor, [packet receivingInPort]); + if (connection && [connection isValid]) + { + rmc = [NSPortCoder newDecodingWithPacket: packet + connection: connection]; + [[rmc connection] _handleRmc: rmc]; + } + else + { + [packet release]; /* Discard data on invalid connection. */ + } +} + +- (int) _newMsgNumber +{ + int n; + + NSParameterAssert (is_valid); + [sequenceNumberGate lock]; + n = message_count++; + [sequenceNumberGate unlock]; + return n; +} + + + +/* Managing objects and proxies. */ +- (void) addLocalObject: anObj +{ + id object = [anObj localForProxy]; + unsigned target; + GSLocalCounter *counter; + + NSParameterAssert (is_valid); + [proxiesHashGate lock]; + /* xxx Do we need to check to make sure it's not already there? */ + /* This retains object. */ + NSMapInsert(local_objects, (void*)object, anObj); + + /* + * Keep track of local objects accross all connections. + */ + counter = NSMapGet(all_connections_local_objects, (void*)object); + if (counter) + { + counter->ref++; + target = counter->target; + } + else + { + counter = [GSLocalCounter newWithObject: object]; + target = counter->target; + NSMapInsert(all_connections_local_objects, (void*)object, counter); + NSMapInsert(all_connections_local_targets, (void*)target, counter); + [counter release]; + } + [anObj setProxyTarget: target]; + NSMapInsert(local_targets, (void*)target, anObj); + if (debug_connection > 2) + NSLog(@"add local object (0x%x) target (0x%x) " + @"to connection (0x%x) (ref %d)\n", + (gsaddr)object, target, (gsaddr) self, counter->ref); + [proxiesHashGate unlock]; +} + +- (NSDistantObject*) localForObject: (id)object +{ + NSDistantObject *p; + + /* Don't assert (is_valid); */ + [proxiesHashGate lock]; + p = NSMapGet (local_objects, (void*)object); + [proxiesHashGate unlock]; + NSParameterAssert(!p || [p connectionForProxy] == self); + return p; +} + +/* This should get called whenever an object free's itself */ ++ (void) removeLocalObject: (id)anObj +{ + NSHashEnumerator enumerator; + NSConnection *o; + + enumerator = NSEnumerateHashTable(connection_table); + while ((o = (NSConnection*)NSNextHashEnumeratorItem(&enumerator)) != nil) + { + [o removeLocalObject: anObj]; + } +} + +- (void) removeLocalObject: anObj +{ + NSDistantObject *prox; + unsigned target; + GSLocalCounter *counter; + unsigned val = 0; + + [proxiesHashGate lock]; + + prox = NSMapGet(local_objects, (void*)anObj); + target = [prox targetForProxy]; + + /* + * If all references to a local proxy have gone - remove the + * global reference as well. + */ + counter = NSMapGet(all_connections_local_objects, (void*)anObj); + if (counter) + { + counter->ref--; + if ((val = counter->ref) == 0) + { + /* + * If this proxy has been vended onwards by another process, we + * need to keep a reference to the local object around for a + * while in case that other process needs it. + */ + if (0) + { + id item; + if (timer == nil) + { + timer = [NSTimer scheduledTimerWithTimeInterval: 1.0 + target: [NSConnection class] + selector: @selector(_timeout:) + userInfo: nil + repeats: YES]; + } + item = [CachedLocalObject itemWithObject: counter time: 30]; + NSMapInsert(all_connections_local_cached, (void*)target, item); + if (debug_connection > 3) + NSLog(@"placed local object (0x%x) target (0x%x) in cache", + (gsaddr)anObj, target); + } + NSMapRemove(all_connections_local_objects, (void*)anObj); + NSMapRemove(all_connections_local_targets, (void*)target); + } + } + + NSMapRemove(local_objects, (void*)anObj); + NSMapRemove(local_targets, (void*)target); + + if (debug_connection > 2) + NSLog(@"remove local object (0x%x) target (0x%x) " + @"from connection (0x%x) (ref %d)\n", + (gsaddr)anObj, target, (gsaddr)self, val); + + [proxiesHashGate unlock]; +} + +- (void) _release_targets: (unsigned*)list count: (unsigned)number +{ + NS_DURING + { + /* + * Tell the remote app that it can release its local objects + * for the targets in the specified list since we don't have + * proxies for them any more. + */ + if (receive_port && is_valid && number > 0) { + id op; + unsigned i; + + op = [[self encodingClass] + newForWritingWithConnection: self + sequenceNumber: [self _newMsgNumber] + identifier: PROXY_RELEASE]; + + [op encodeValueOfCType: @encode(unsigned) + at: &number + withName: NULL]; + + for (i = 0; i < number; i++) + { + [op encodeValueOfCType: @encode(unsigned) + at: &list[i] + withName: NULL]; + if (debug_connection > 3) + NSLog(@"sending release for target (0x%x) on (0x%x)", + list[i], (gsaddr)self); + } + + [op dismiss]; + } + } + NS_HANDLER + { + if (debug_connection) + NSLog(@"failed to release targets - %@\n", [localException name]); + } + NS_ENDHANDLER +} + +- (void) retainTarget: (unsigned)target +{ + NS_DURING + { + /* + * Tell the remote app that it must retain the local object + * for the target on this connection. + */ + if (receive_port && is_valid) + { + id op; + id ip; + id result; + int seq_num = [self _newMsgNumber]; + + op = [[self encodingClass] + newForWritingWithConnection: self + sequenceNumber: seq_num + identifier: PROXY_RETAIN]; + + [op encodeValueOfCType: @encode(typeof(target)) + at: &target + withName: NULL]; + + [op dismiss]; + ip = [self _getReceivedReplyRmcWithSequenceNumber: seq_num]; + [ip decodeObjectAt: &result withName: NULL]; + if (result != nil) + NSLog(@"failed to retain target - %@\n", result); + [ip dismiss]; + } + } + NS_HANDLER + { + NSLog(@"failed to retain target - %@\n", [localException name]); + } + NS_ENDHANDLER +} + +- (void) removeProxy: (NSDistantObject*)aProxy +{ + unsigned target = [aProxy targetForProxy]; + + /* Don't assert (is_valid); */ + [proxiesHashGate lock]; + /* This also releases aProxy */ + NSMapRemove (remote_proxies, (void*)target); + [proxiesHashGate unlock]; + + /* + * Tell the remote application that we have removed our proxy and + * it can release it's local object. + */ + [self _release_targets: &target count: 1]; +} + +- (NSArray*) localObjects +{ + NSArray *c; + + /* Don't assert (is_valid); */ + [proxiesHashGate lock]; + c = NSAllMapTableValues(local_objects); + [proxiesHashGate unlock]; + return c; +} + +- (NSArray*) proxies +{ + NSArray *c; + + /* Don't assert (is_valid); */ + [proxiesHashGate lock]; + c = NSAllMapTableValues(remote_proxies); + [proxiesHashGate unlock]; + return c; +} + +- (NSDistantObject*) proxyForTarget: (unsigned)target +{ + NSDistantObject *p; + + /* Don't assert (is_valid); */ + [proxiesHashGate lock]; + p = NSMapGet (remote_proxies, (void*)target); + [proxiesHashGate unlock]; + NSParameterAssert(!p || [p connectionForProxy] == self); + return p; +} + +- (void) addProxy: (NSDistantObject*) aProxy +{ + unsigned target = (unsigned int)[aProxy targetForProxy]; + + NSParameterAssert (is_valid); + NSParameterAssert(aProxy->isa == [NSDistantObject class]); + NSParameterAssert([aProxy connectionForProxy] == self); + [proxiesHashGate lock]; + if (NSMapGet (remote_proxies, (void*)target)) + { + [proxiesHashGate unlock]; + [NSException raise: NSGenericException + format: @"Trying to add the same proxy twice"]; + } + NSMapInsert (remote_proxies, (void*)target, aProxy); + [proxiesHashGate unlock]; +} + +- (id) includesProxyForTarget: (unsigned)target +{ + NSDistantObject *ret; + + /* Don't assert (is_valid); */ + [proxiesHashGate lock]; + ret = NSMapGet (remote_proxies, (void*)target); + [proxiesHashGate unlock]; + return ret; +} + +- (id) includesLocalObject: (id)anObj +{ + NSDistantObject* ret; + + /* Don't assert (is_valid); */ + [proxiesHashGate lock]; + ret = NSMapGet(local_objects, (void*)anObj); + [proxiesHashGate unlock]; + return ret; +} + +- (id) includesLocalTarget: (unsigned)target +{ + NSDistantObject* ret; + + /* Don't assert (is_valid); */ + [proxiesHashGate lock]; + ret = NSMapGet(local_targets, (void*)target); + [proxiesHashGate unlock]; + return ret; +} + +/* Check all connections. + Proxy needs to use this when decoding a local object in order to + make sure the target address is a valid object. It is not enough + for the Proxy to check the Proxy's connection only (using + -includesLocalTarget), because the proxy may have come from a + triangle connection. */ ++ (id) includesLocalTarget: (unsigned)target +{ + id ret; + + /* Don't assert (is_valid); */ + NSParameterAssert (all_connections_local_targets); + [proxiesHashGate lock]; + ret = NSMapGet (all_connections_local_targets, (void*)target); + [proxiesHashGate unlock]; + return ret; +} + + +/* Pass nil to remove any reference keyed by aPort. */ ++ (void) setRootObject: anObj forInPort: (NSPort*)aPort +{ + id oldRootObject = [self rootObjectForInPort: aPort]; + + NSParameterAssert ([aPort isValid]); + /* xxx This retains aPort? How will aPort ever get dealloc'ed? */ + if (oldRootObject != anObj) + { + if (anObj) + { + [root_object_dictionary_gate lock]; + [root_object_dictionary setObject: anObj forKey: aPort]; + [root_object_dictionary_gate unlock]; + } + else /* anObj == nil && oldRootObject != nil */ + { + [root_object_dictionary_gate lock]; + [root_object_dictionary removeObjectForKey: aPort]; + [root_object_dictionary_gate unlock]; + } + } +} + ++ rootObjectForInPort: (NSPort*)aPort +{ + id ro; + + [root_object_dictionary_gate lock]; + ro = [root_object_dictionary objectForKey: aPort]; + [root_object_dictionary_gate unlock]; + return ro; +} + + +/* Accessing ivars */ + +- (Class) receivePortClass +{ + return receive_port_class; +} + +- (Class) sendPortClass +{ + return send_port_class; +} + +- (void) setReceivePortClass: (Class) aPortClass +{ + receive_port_class = aPortClass; +} + +- (void) setSendPortClass: (Class) aPortClass +{ + send_port_class = aPortClass; +} + +- (Class) proxyClass +{ + /* we might replace this with a per-Connection proxy class. */ + return default_proxy_class; +} + +- (Class) encodingClass +{ + return encoding_class; +} + +- (Class) decodingClass +{ + /* we might replace this with a per-Connection class. */ + return default_decoding_class; +} + + +/* Prevent trying to encode the connection itself */ + +- (void) encodeWithCoder: anEncoder +{ + [self shouldNotImplement: _cmd]; +} + ++ newWithCoder: aDecoder; +{ + [self shouldNotImplement: _cmd]; + return self; +} + + +/* Shutting down and deallocating. */ + +/* + * We register this method for a notification when a port dies. + * NB. It is possible that the death of a port could be notified + * to us after we are invalidated - in which case we must ignore it. + */ +- (void) portIsInvalid: notification +{ + if (is_valid) + { + id port = [notification object]; + + if (debug_connection) + { + NSLog(@"Received port invalidation notification for " + @"connection 0x%x\n\t%@\n", (gsaddr)self, port); + } + + /* We shouldn't be getting any port invalidation notifications, + except from our own ports; this is how we registered ourselves + with the NSNotificationCenter in + +newForInPort: outPort: ancestorConnection. */ + NSParameterAssert (port == receive_port || port == send_port); + + [self invalidate]; + } +} + +@end + + + +@implementation NSConnection (OPENSTEP) + ++ (NSConnection*) connectionWithReceivePort: (NSPort*)r + sendPort: (NSPort*)s +{ + NSConnection *c; + + c = [self alloc]; + c = [self initWithReceivePort: r sendPort: s]; + return AUTORELEASE(c); +} + +/* This is the designated initializer for NSConnection */ +- (id) initWithReceivePort: (NSPort*)r + sendPort: (NSPort*)s +{ + NSNotificationCenter *nCenter; + NSConnection *conn; + id del; + + NSParameterAssert(r); + + /* + * Find previously existing connection if there + */ + conn = [NSConnection connectionByInPort: r outPort: s]; + if (conn != nil) + { + if (debug_connection > 2) + { + NSLog(@"Found existing connection (0x%x) for \n\t%@\n\t%@\n", + (gsaddr)conn, r, s); + } + RELEASE(self); + return RETAIN(conn); + } + [connection_table_gate lock]; + + if (debug_connection) + { + NSLog(@"Initialised new connection 0x%x\n\t%@\n\t%@\n", + (gsaddr)self, r, s); + } + is_valid = YES; + receive_port = RETAIN(r); + send_port = RETAIN(s); + message_count = 0; + rep_out_count = 0; + req_out_count = 0; + rep_in_count = 0; + req_in_count = 0; + + /* + * This maps (void*)obj to (id)obj. The obj's are retained. + * We use this instead of an NSHashTable because we only care about + * the object's address, and don't want to send the -hash message to it. + */ + local_objects = + NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks, + NSObjectMapValueCallBacks, 0); + + /* + * This maps handles for local objects to their local proxies. + */ + local_targets = + NSCreateMapTable(NSIntMapKeyCallBacks, + NSNonOwnedPointerMapValueCallBacks, 0); + + /* + * This maps [proxy targetForProxy] to proxy. The proxy's are retained. + */ + remote_proxies = + NSCreateMapTable(NSIntMapKeyCallBacks, + NSNonOwnedPointerMapValueCallBacks, 0); + + reply_timeout = default_reply_timeout; + request_timeout = default_request_timeout; + encoding_class = default_encoding_class; + + /* xxx It this the correct behavior? */ + if ((conn = NSMapGet(receive_port_2_ancestor, r)) == nil) + { + NSMapInsert(receive_port_2_ancestor, r, self); + /* + * This will cause the connection with the registered name + * to receive the -invokeWithObject: from the IN_PORT. + * This ends up being the ancestor of future new NSConnections + * on this in port. + */ + /* xxx Could it happen that this connection was invalidated, but + the others would still be OK? That would cause problems. + No. I don't think that can happen. */ + [(InPort*)r setReceivedPacketInvocation: (id)[self class]]; + } + + if (conn != nil) + { + receive_port_class = [conn receivePortClass]; + send_port_class = [conn sendPortClass]; + } + else + { + receive_port_class = default_receive_port_class; + send_port_class = default_send_port_class; + } + independent_queueing = NO; + request_depth = 0; + delegate = nil; + /* + * Set up request modes array and make sure the receiving port is + * added to the run loop to get data. + */ + request_modes + = RETAIN([NSMutableArray arrayWithObject: NSDefaultRunLoopMode]); + [[NSRunLoop currentRunLoop] addPort: (NSPort*)r + forMode: NSDefaultRunLoopMode]; + [[NSRunLoop currentRunLoop] addPort: (NSPort*)r + forMode: NSConnectionReplyMode]; + + /* Ask the delegate for permission, (OpenStep-style and GNUstep-style). */ + + /* Preferred OpenStep version, which just allows the returning of BOOL */ + del = [conn delegate]; + if ([del respondsTo: @selector(connection:shouldMakeNewConnection:)]) + { + if ([del connection: conn shouldMakeNewConnection: self] == NO) + { + [connection_table_gate unlock]; + RELEASE(self); + return nil; + } + } + /* Deprecated OpenStep version, which just allows the returning of BOOL */ + if ([del respondsTo: @selector(makeNewConnection:sender:)]) + { + if (![del makeNewConnection: self sender: conn]) + { + [connection_table_gate unlock]; + RELEASE(self); + return nil; + } + } + /* Here is the GNUstep version, which allows the delegate to specify + a substitute. Note: The delegate is responsible for freeing + newConn if it returns something different. */ + if ([del respondsTo: @selector(connection:didConnect:)]) + self = [del connection: conn didConnect: self]; + + /* Register ourselves for invalidation notification when the + ports become invalid. */ + nCenter = [NSNotificationCenter defaultCenter]; + [nCenter addObserver: self + selector: @selector(portIsInvalid:) + name: NSPortDidBecomeInvalidNotification + object: r]; + if (s != nil) + [nCenter addObserver: self + selector: @selector(portIsInvalid:) + name: NSPortDidBecomeInvalidNotification + object: s]; + + /* In order that connections may be deallocated - there is an + implementation of [-release] to automatically remove the connection + from this array when it is the only thing retaining it. */ + NSHashInsert(connection_table, (void*)self); + [connection_table_gate unlock]; + + [[NSNotificationCenter defaultCenter] + postNotificationName: NSConnectionDidInitializeNotification + object: self]; + + return self; +} + +- (NSPort*) receivePort +{ + return receive_port; +} + +- (void) runInNewThread +{ + [self notImplemented: _cmd]; +} + +- (NSPort*) sendPort +{ + return send_port; +} + +@end +#endif diff --git a/Old/OldNSPortCoder.h b/Old/OldNSPortCoder.h new file mode 100644 index 000000000..580949bc9 --- /dev/null +++ b/Old/OldNSPortCoder.h @@ -0,0 +1,147 @@ +/* Interface for NSPortCoder object for distributed objects + Copyright (C) 2000 Free Software Foundation, Inc. + + Written by: Richard Frith-Macdonald + Date: June 2000 + + 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 __NSPortCoder_h +#define __NSPortCoder_h + +#include + +@class NSMutableArray; +@class NSMutableDictionary; +@class NSConnection; +@class NSPort; + +@interface NSPortCoder : NSCoder +{ +@private + NSMutableArray *_comp; + NSConnection *_conn; + BOOL _is_by_copy; + BOOL _is_by_ref; +// Encoding + BOOL _encodingRoot; + BOOL _initialPass; + id _dst; /* Serialization destination. */ + IMP _eObjImp; /* Method to encode an id. */ + IMP _eValImp; /* Method to encode others. */ +#ifndef _IN_PORT_CODER_M +#define GSIMapTable void* +#endif + GSIMapTable _clsMap; /* Class cross references. */ + GSIMapTable _cIdMap; /* Conditionally coded. */ + GSIMapTable _uIdMap; /* Unconditionally coded. */ + GSIMapTable _ptrMap; /* Constant pointers. */ +#ifndef _IN_PORT_CODER_M +#undef GSIMapTable +#endif + unsigned _xRefC; /* Counter for cross-reference. */ + unsigned _xRefO; /* Counter for cross-reference. */ + unsigned _xRefP; /* Counter for cross-reference. */ +// Decoding + id _src; /* Deserialization source. */ + IMP _dDesImp; /* Method to deserialize with. */ + void (*_dTagImp)(id,SEL,unsigned char*,unsigned*,unsigned*); + IMP _dValImp; /* Method to decode data with. */ +#ifndef _IN_PORT_CODER_M +#define GSIArray void* +#endif + GSIArray _clsAry; /* Class crossreference map. */ + GSIArray _objAry; /* Object crossreference map. */ + GSIArray _ptrAry; /* Pointer crossreference map. */ +#ifndef _IN_PORT_CODER_M +#undef GSIArray +#endif + NSMutableDictionary *_cInfo; /* Class version information. */ + unsigned _cursor; /* Position in data buffer. */ + unsigned _version; /* Version of archiver used. */ + NSZone *_zone; /* Zone for allocating objs. */ +} + ++ (NSPortCoder*) portCoderWithReceivePort: (NSPort*)recv + sendPort: (NSPort*)send + components: (NSArray*)comp; +- (id) initWithReceivePort: (NSPort*)recv + sendPort: (NSPort*)send + components: (NSArray*)comp; + +- (NSConnection*) connection; +- (NSPort*) decodePortObject; +- (void) dispatch; +- (void) encodePortObject: (NSPort*)aPort; +- (BOOL) isBycopy; +- (BOOL) isByref; + +@end + +@interface NSPortCoder (Private) +- (NSMutableArray*) _components; +@end + + +#endif /* __NSPortCoder_h */ +#else +/* Interface for NSPortCoder object for distributed objects + Copyright (C) 1997 Free Software Foundation, Inc. + + Written by: Richard Frith-Macdonald + Date: August 1997 + + 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 __NSPortCoder_h +#define __NSPortCoder_h + +#include + +@class NSConnection; +@class NSPort; + +@interface NSPortCoder : NSCoder +{ +} + +- (NSConnection*) connection; +- (NSPort*) decodePortObject; +- (void) encodePortObject: (NSPort*)aPort; +- (BOOL) isBycopy; +- (BOOL) isByref; + +@end + + +#endif /* __NSPortCoder_h */ diff --git a/Old/OldNSPortCoder.m b/Old/OldNSPortCoder.m new file mode 100644 index 000000000..fe6d089c3 --- /dev/null +++ b/Old/OldNSPortCoder.m @@ -0,0 +1,2437 @@ +/* Implementation of NSPortCoder object for remote messaging + Copyright (C) 1997,2000 Free Software Foundation, Inc. + + This implementation for OPENSTEP conformance written by + Richard Frith-Macdonald + Created: August 1997, rewritten June 2000 + + based on original code - + + Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: July 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. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * Setup for inline operation of pointer map tables. + */ +#define GSI_MAP_RETAIN_KEY(X) +#define GSI_MAP_RELEASE_KEY(X) +#define GSI_MAP_RETAIN_VAL(X) +#define GSI_MAP_RELEASE_VAL(X) +#define GSI_MAP_HASH(X) ((X).uint) +#define GSI_MAP_EQUAL(X,Y) ((X).uint == (Y).uint) + +#include + +/* + * Setup for inline operation of arrays. + */ +#define GSI_ARRAY_RETAIN(X) +#define GSI_ARRAY_RELEASE(X) +#define GSI_ARRAY_TYPES GSUNION_OBJ|GSUNION_SEL|GSUNION_STR + +#include + + + +#define _IN_PORT_CODER_M +#include +#undef _IN_PORT_CODER_M + +#include + +static BOOL debug_port_coder = NO; + +typedef unsigned char uchar; + +#define PREFIX "GNUstep DO archive" + +static SEL eSerSel = @selector(serializeDataAt:ofObjCType:context:); +static SEL eTagSel = @selector(serializeTypeTag:); +static SEL xRefSel = @selector(serializeTypeTag:andCrossRef:); +static SEL eObjSel = @selector(encodeObject:); +static SEL eValSel = @selector(encodeValueOfObjCType:at:); +static SEL dDesSel = @selector(deserializeDataAt:ofObjCType:atCursor:context:); +static SEL dTagSel = @selector(deserializeTypeTag:andCrossRef:atCursor:); +static SEL dValSel = @selector(decodeValueOfObjCType:at:); + + + +static const char* +typeToName1(char type) +{ + switch (type) + { + case _C_CLASS: return "class"; + case _C_ID: return "object"; + case _C_SEL: return "selector"; + case _C_CHR: return "char"; + case _C_UCHR: return "unsigned char"; + case _C_SHT: return "short"; + case _C_USHT: return "unsigned short"; + case _C_INT: return "int"; + case _C_UINT: return "unsigned int"; + case _C_LNG: return "long"; + case _C_ULNG: return "unsigned long"; + case _C_LNG_LNG: return "long long"; + case _C_ULNG_LNG: return "unsigned long long"; + case _C_FLT: return "float"; + case _C_DBL: return "double"; + case _C_PTR: return "pointer"; + case _C_CHARPTR: return "cstring"; + case _C_ARY_B: return "array"; + case _C_STRUCT_B: return "struct"; + default: + { + static char buf1[32]; + static char buf2[32]; + static char *bufptr = buf1; + + if (bufptr == buf1) + { + bufptr = buf2; + } + else + { + bufptr = buf1; + } + sprintf(bufptr, "unknown type info - 0x%x", type); + return bufptr; + } + } +} + +static const char* +typeToName2(char type) +{ + switch (type & _GSC_MASK) + { + case _GSC_CLASS: return "class"; + case _GSC_ID: return "object"; + case _GSC_SEL: return "selector"; + case _GSC_CHR: return "char"; + case _GSC_UCHR: return "unsigned char"; + case _GSC_SHT: return "short"; + case _GSC_USHT: return "unsigned short"; + case _GSC_INT: return "int"; + case _GSC_UINT: return "unsigned int"; + case _GSC_LNG: return "long"; + case _GSC_ULNG: return "unsigned long"; + case _GSC_LNG_LNG: return "long long"; + case _GSC_ULNG_LNG: return "unsigned long long"; + case _GSC_FLT: return "float"; + case _GSC_DBL: return "double"; + case _GSC_PTR: return "pointer"; + case _GSC_CHARPTR: return "cstring"; + case _GSC_ARY_B: return "array"; + case _GSC_STRUCT_B: return "struct"; + default: + { + static char buf1[32]; + static char buf2[32]; + static char *bufptr = buf1; + + if (bufptr == buf1) + { + bufptr = buf2; + } + else + { + bufptr = buf1; + } + sprintf(bufptr, "unknown type info - 0x%x", type); + return bufptr; + } + } +} + +/* + * There are thirtyone possible basic types. We reserve a type of zero + * to mean that no information is specified. The slots in this array + * MUST correspond to the definitions in NSData.h + */ +static char type_map[32] = { + 0, + _C_CHR, + _C_UCHR, + _C_SHT, + _C_USHT, + _C_INT, + _C_UINT, + _C_LNG, + _C_ULNG, +#ifdef _C_LNG_LNG + _C_LNG_LNG, + _C_ULNG_LNG, +#else + 0, + 0, +#endif + _C_FLT, + _C_DBL, + 0, + 0, + 0, + _C_ID, + _C_CLASS, + _C_SEL, + _C_PTR, + _C_CHARPTR, + _C_ARY_B, + _C_STRUCT_B, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 +}; + +static inline void +typeCheck(char t1, char t2) +{ + if (type_map[(t2 & _GSC_MASK)] != t1) + { + [NSException raise: NSInternalInconsistencyException + format: @"expected %s and got %s", + typeToName1(t1), typeToName2(t2)]; + } +} + +@interface GSClassInfo : NSObject +{ +@public + Class class; + unsigned version; + NSString *name; +} ++ (id) newWithClass: (Class)c andVersion: (unsigned)v; +- (NSString*) className; +@end + +@implementation GSClassInfo ++ (id) newWithClass: (Class)c andVersion: (unsigned)v; +{ + GSClassInfo *info; + + info = (GSClassInfo*)NSAllocateObject(self, 0, NSDefaultMallocZone()); + if (info != nil) + { + info->class = c; + info->version = v; + } + return info; +} +- (NSString*) className +{ + if (name == nil) + { + name = RETAIN(NSStringFromClass(class)); + } + return name; +} +- (void) dealloc +{ + TEST_RELEASE(name); + NSDeallocateObject(self); +} +@end + + + + + +@interface NSPortCoder (Headers) +- (void) _deserializeHeaderAt: (unsigned*)pos + version: (unsigned*)v + classes: (unsigned*)c + objects: (unsigned*)o + pointers: (unsigned*)p; +- (void) _serializeHeaderAt: (unsigned)pos + version: (unsigned)v + classes: (unsigned)c + objects: (unsigned)o + pointers: (unsigned)p; +@end + + +@implementation NSPortCoder + +@class NSMutableDataMalloc; + +static Class connectionClass; +static Class mutableArrayClass; +static Class mutableDataClass; +static Class mutableDictionaryClass; + +static IMP _eSerImp; /* Method to serialize with. */ +static IMP _eTagImp; /* Serialize a type tag. */ +static IMP _xRefImp; /* Serialize a crossref. */ + ++ (void) initialize +{ + if (self == [NSPortCoder class]) + { + connectionClass = [NSConnection class]; + mutableArrayClass = [NSMutableArray class]; + mutableDataClass = [NSMutableDataMalloc class]; + _eSerImp = [mutableDataClass instanceMethodForSelector: eSerSel]; + _eTagImp = [mutableDataClass instanceMethodForSelector: eTagSel]; + _xRefImp = [mutableDataClass instanceMethodForSelector: xRefSel]; + mutableDictionaryClass = [NSMutableDictionary class]; + } +} + ++ (NSPortCoder*) portCoderWithReceivePort: (NSPort*)recv + sendPort: (NSPort*)send + components: (NSArray*)comp; +{ + id coder; + + coder = [self allocWithZone: NSDefaultMallocZone()]; + coder = [coder initWithReceivePort: recv sendPort: send components: comp]; + AUTORELEASE(coder); + return coder; +} + +- (NSConnection*) connection +{ + return _conn; +} + +- (void) dealloc +{ + RELEASE(_dst); /* Decoders retain their output data object. */ + RELEASE(_comp); + RELEASE(_conn); + RELEASE(_cInfo); + if (_clsMap != 0) + { + GSIMapEmptyMap(_clsMap); + GSIMapEmptyMap(_cIdMap); + GSIMapEmptyMap(_uIdMap); + GSIMapEmptyMap(_ptrMap); + NSZoneFree(_clsMap->zone, (void*)_clsMap); + } + if (_clsAry != 0) + { + unsigned count = GSIArrayCount(_clsAry); + + while (count-- > 0) + { + RELEASE(GSIArrayItemAtIndex(_clsAry, count).obj); + } + GSIArrayClear(_clsAry); + GSIArrayClear(_objAry); + GSIArrayClear(_ptrAry); + NSZoneFree(_clsAry->zone, (void*)_clsAry); + } + + [super dealloc]; +} + +- (void) decodeArrayOfObjCType: (const char*)type + count: (unsigned)expected + at: (void*)buf +{ + int i; + int offset = 0; + int size = objc_sizeof_type(type); + unsigned char info; + unsigned count; + + (*_dTagImp)(_src, dTagSel, &info, 0, &_cursor); + (*_dDesImp)(_src, dDesSel, &count, @encode(unsigned), &_cursor, nil); + if (info != _GSC_ARY_B) + { + [NSException raise: NSInternalInconsistencyException + format: @"expected array and got %s", typeToName2(info)]; + } + if (count != expected) + { + [NSException raise: NSInternalInconsistencyException + format: @"expected array count %u and got %u", + expected, count]; + } + + switch (*type) + { + case _C_ID: info = _GSC_NONE; break; + case _C_CHR: info = _GSC_CHR; break; + case _C_UCHR: info = _GSC_UCHR; break; + case _C_SHT: info = _GSC_SHT; break; + case _C_USHT: info = _GSC_USHT; break; + case _C_INT: info = _GSC_INT; break; + case _C_UINT: info = _GSC_UINT; break; + case _C_LNG: info = _GSC_LNG; break; + case _C_ULNG: info = _GSC_ULNG; break; +#ifdef _C_LNG_LNG + case _C_LNG_LNG: info = _GSC_LNG_LNG; break; + case _C_ULNG_LNG: info = _GSC_ULNG_LNG; break; +#endif + case _C_FLT: info = _GSC_FLT; break; + case _C_DBL: info = _GSC_DBL; break; + default: info = _GSC_NONE; break; + } + + if (info == _GSC_NONE) + { + for (i = 0; i < count; i++) + { + (*_dValImp)(self, dValSel, type, (char*)buf + offset); + offset += size; + } + } + else + { + unsigned char ainfo; + + (*_dTagImp)(_src, dTagSel, &ainfo, 0, &_cursor); + if (info != (ainfo & _GSC_MASK)) + { + [NSException raise: NSInternalInconsistencyException + format: @"expected %s and got %s", + typeToName2(info), typeToName2(ainfo)]; + } + + for (i = 0; i < count; i++) + { + (*_dDesImp)(_src, dDesSel, (char*)buf + offset, type, &_cursor, nil); + offset += size; + } + } +} + +- (NSData*) decodeDataObject +{ + int pos; + + [self decodeValueOfObjCType: @encode(int) at: &pos]; + if (pos >= 0) + { + return [_comp objectAtIndex: pos]; + } + else if (pos == -1) + { + return nil; + } + else if (pos == -2) + { + return [mutableDataClass data]; + } + else + { + [NSException raise: NSInternalInconsistencyException + format: @"Bad tag (%d) decoding data object", pos]; + return nil; + } +} + +- (NSPort*) decodePortObject +{ + unsigned pos; + + [self decodeValueOfObjCType: @encode(unsigned) at: &pos]; + return [_comp objectAtIndex: pos]; +} + +/* + * The [-decodeObject] method is implemented purely for performance - + * It duplicates the code for handling objects in the + * [-decodeValueOfObjCType:at:] method above, but differs in that the + * resulting object is autoreleased when it comes from this method. + */ +- (id) decodeObject +{ + unsigned char info; + unsigned xref; + id obj; + + (*_dTagImp)(_src, dTagSel, &info, &xref, &_cursor); + if ((info & _GSC_MASK) != _GSC_ID) + { + [NSException raise: NSInternalInconsistencyException + format: @"expected object and got %s", typeToName2(info)]; + } + + /* + * Special case - a zero crossref value is a nil pointer. + */ + if ((info & _GSC_SIZE) == 0) + { + return nil; + } + + if (info & _GSC_XREF) + { + if (xref >= GSIArrayCount(_objAry)) + { + [NSException raise: NSInternalInconsistencyException + format: @"object crossref missing - %d", + xref]; + } + obj = GSIArrayItemAtIndex(_objAry, xref).obj; + /* + * If it's a cross-reference, we don't need to autorelease it + * since we didn't create it. + */ + return obj; + } + else + { + Class c; + id rep; + + if (xref != GSIArrayCount(_objAry)) + { + [NSException raise: NSInternalInconsistencyException + format: @"extra object crossref - %d", + xref]; + } + (*_dValImp)(self, dValSel, @encode(Class), &c); + + obj = [c allocWithZone: _zone]; + GSIArrayAddItem(_objAry, (GSIArrayItem)obj); + + rep = [obj initWithCoder: self]; + if (rep != obj) + { + obj = rep; + GSIArraySetItemAtIndex(_objAry, (GSIArrayItem)obj, xref); + } + + rep = [obj awakeAfterUsingCoder: self]; + if (rep != obj) + { + obj = rep; + GSIArraySetItemAtIndex(_objAry, (GSIArrayItem)obj, xref); + } + /* + * A newly allocated object needs to be autoreleased. + */ + return AUTORELEASE(obj); + } +} + +- (void) decodeValueOfObjCType: (const char*)type + at: (void*)address +{ + unsigned xref; + unsigned char info; +#if GS_HAVE_I128 + gsu128 bigval; +#else +#if GS_HAVE_I64 + gsu64 bigval; +#else + gsu32 bigval; +#endif +#endif + + (*_dTagImp)(_src, dTagSel, &info, &xref, &_cursor); + + switch (info & _GSC_MASK) + { + case _GSC_ID: + { + id obj; + + typeCheck(*type, _GSC_ID); + /* + * Special case - a zero crossref value size is a nil pointer. + */ + if ((info & _GSC_SIZE) == 0) + { + obj = nil; + } + else + { + if (info & _GSC_XREF) + { + if (xref >= GSIArrayCount(_objAry)) + { + [NSException raise: NSInternalInconsistencyException + format: @"object crossref missing - %d", + xref]; + } + obj = GSIArrayItemAtIndex(_objAry, xref).obj; + /* + * If it's a cross-reference, we need to retain it in + * order to give the appearance that it's actually a + * new object. + */ + IF_NO_GC(RETAIN(obj)); + } + else + { + Class c; + id rep; + + if (xref != GSIArrayCount(_objAry)) + { + [NSException raise: NSInternalInconsistencyException + format: @"extra object crossref - %d", + xref]; + } + (*_dValImp)(self, dValSel, @encode(Class), &c); + + obj = [c allocWithZone: _zone]; + GSIArrayAddItem(_objAry, (GSIArrayItem)obj); + + rep = [obj initWithCoder: self]; + if (rep != obj) + { + obj = rep; + GSIArraySetItemAtIndex(_objAry, (GSIArrayItem)obj, xref); + } + + rep = [obj awakeAfterUsingCoder: self]; + if (rep != obj) + { + obj = rep; + GSIArraySetItemAtIndex(_objAry, (GSIArrayItem)obj, xref); + } + } + } + *(id*)address = obj; + return; + } + + case _GSC_CLASS: + { + Class c; + GSClassInfo *classInfo; + Class dummy; + + typeCheck(*type, _GSC_CLASS); + /* + * Special case - a zero crossref value size is a nil pointer. + */ + if ((info & _GSC_SIZE) == 0) + { + *(SEL*)address = 0; + return; + } + if (info & _GSC_XREF) + { + if (xref >= GSIArrayCount(_clsAry)) + { + [NSException raise: NSInternalInconsistencyException + format: @"class crossref missing - %d", xref]; + } + classInfo = (GSClassInfo*)GSIArrayItemAtIndex(_clsAry, xref).obj; + *(Class*)address = classInfo->class; + return; + } + while ((info & _GSC_MASK) == _GSC_CLASS) + { + unsigned cver; + + if (xref != GSIArrayCount(_clsAry)) + { + [NSException raise: NSInternalInconsistencyException + format: @"extra class crossref - %d", xref]; + } + (*_dDesImp)(_src, dDesSel, &c, @encode(Class), &_cursor, nil); + (*_dDesImp)(_src, dDesSel, &cver, @encode(unsigned), &_cursor, + nil); + if (c == 0) + { + [NSException raise: NSInternalInconsistencyException + format: @"decoded nil class"]; + } + classInfo = [GSClassInfo newWithClass: c andVersion: cver]; + GSIArrayAddItem(_clsAry, (GSIArrayItem)classInfo); + *(Class*)address = classInfo->class; + /* + * Point the address to a dummy location and read the + * next tag - if it is another class, loop to get it. + */ + address = &dummy; + (*_dTagImp)(_src, dTagSel, &info, &xref, &_cursor); + } + if (info != _GSC_NONE) + { + [NSException raise: NSInternalInconsistencyException + format: @"class list improperly terminated"]; + } + return; + } + + case _GSC_SEL: + { + SEL sel; + + typeCheck(*type, _GSC_SEL); + /* + * Special case - a zero crossref value size is a nil pointer. + */ + if ((info & _GSC_SIZE) == 0) + { + *(SEL*)address = 0; + return; + } + if (info & _GSC_XREF) + { + if (xref >= GSIArrayCount(_ptrAry)) + { + [NSException raise: NSInternalInconsistencyException + format: @"sel crossref missing - %d", xref]; + } + sel = GSIArrayItemAtIndex(_ptrAry, xref).sel; + } + else + { + if (xref != GSIArrayCount(_ptrAry)) + { + [NSException raise: NSInternalInconsistencyException + format: @"extra sel crossref - %d", xref]; + } + (*_dDesImp)(_src, dDesSel, &sel, @encode(SEL), &_cursor, nil); + GSIArrayAddItem(_ptrAry, (GSIArrayItem)sel); + } + *(SEL*)address = sel; + return; + } + + case _GSC_ARY_B: + { + int count; + + typeCheck(*type, _GSC_ARY_B); + count = atoi(++type); + while (isdigit(*type)) + { + type++; + } + [self decodeArrayOfObjCType: type count: count at: address]; + return; + } + + case _GSC_STRUCT_B: + { + int offset = 0; + + typeCheck(*type, _GSC_STRUCT_B); + while (*type != _C_STRUCT_E && *type++ != '='); /* skip "=" */ + for (;;) + { + (*_dValImp)(self, dValSel, type, (char*)address + offset); + offset += objc_sizeof_type(type); + type = objc_skip_typespec(type); + if (*type == _C_STRUCT_E) + { + break; + } + else + { + int align = objc_alignof_type(type); + int rem = offset % align; + + if (rem != 0) + { + offset += align - rem; + } + } + } + return; + } + + case _GSC_PTR: + { + typeCheck(*type, _GSC_PTR); + /* + * Special case - a zero crossref value size is a nil pointer. + */ + if ((info & _GSC_SIZE) == 0) + { + *(void**)address = 0; + return; + } + if (info & _GSC_XREF) + { + if (xref >= GSIArrayCount(_ptrAry)) + { + [NSException raise: NSInternalInconsistencyException + format: @"ptr crossref missing - %d", xref]; + } + *(void**)address = GSIArrayItemAtIndex(_ptrAry, xref).ptr; + } + else + { + unsigned size; + + if (GSIArrayCount(_ptrAry) != xref) + { + [NSException raise: NSInternalInconsistencyException + format: @"extra ptr crossref - %d", xref]; + } + + /* + * Allocate memory for object to be decoded into and + * add it to the crossref map. + */ + size = objc_sizeof_type(++type); + *(void**)address = _fastMallocBuffer(size); + GSIArrayAddItem(_ptrAry, (GSIArrayItem)*(void**)address); + + /* + * Decode value and add memory to map for crossrefs. + */ + (*_dValImp)(self, dValSel, type, *(void**)address); + } + return; + } + + case _GSC_CHARPTR: + { + typeCheck(*type, _GSC_CHARPTR); + /* + * Special case - a zero crossref value size is a nil pointer. + */ + if ((info & _GSC_SIZE) == 0) + { + *(char**)address = 0; + return; + } + if (info & _GSC_XREF) + { + if (xref >= GSIArrayCount(_ptrAry)) + { + [NSException raise: NSInternalInconsistencyException + format: @"string crossref missing - %d", xref]; + } + *(char**)address = GSIArrayItemAtIndex(_ptrAry, xref).str; + } + else + { + if (xref != GSIArrayCount(_ptrAry)) + { + [NSException raise: NSInternalInconsistencyException + format: @"extra string crossref - %d", xref]; + } + (*_dDesImp)(_src, dDesSel, address, @encode(char*), &_cursor, + nil); + GSIArrayAddItem(_ptrAry, (GSIArrayItem)*(void**)address); + } + return; + } + + case _GSC_CHR: + case _GSC_UCHR: + typeCheck(*type, info & _GSC_MASK); + (*_dDesImp)(_src, dDesSel, address, type, &_cursor, nil); + return; + + case _GSC_SHT: + case _GSC_USHT: + typeCheck(*type, info & _GSC_MASK); + if ((info & _GSC_SIZE) == _GSC_S_SHT) + { + (*_dDesImp)(_src, dDesSel, address, type, &_cursor, nil); + return; + } + break; + + case _GSC_INT: + case _GSC_UINT: + typeCheck(*type, info & _GSC_MASK); + if ((info & _GSC_SIZE) == _GSC_S_INT) + { + (*_dDesImp)(_src, dDesSel, address, type, &_cursor, nil); + return; + } + break; + + case _GSC_LNG: + case _GSC_ULNG: + typeCheck(*type, info & _GSC_MASK); + if ((info & _GSC_SIZE) == _GSC_S_LNG) + { + (*_dDesImp)(_src, dDesSel, address, type, &_cursor, nil); + return; + } + break; + +#ifdef _C_LNG_LNG + case _GSC_LNG_LNG: + case _GSC_ULNG_LNG: + typeCheck(*type, info & _GSC_MASK); + if ((info & _GSC_SIZE) == _GSC_S_LNG_LNG) + { + (*_dDesImp)(_src, dDesSel, address, type, &_cursor, nil); + return; + } + break; + +#endif + case _GSC_FLT: + typeCheck(*type, _GSC_FLT); + (*_dDesImp)(_src, dDesSel, address, type, &_cursor, nil); + return; + + case _GSC_DBL: + typeCheck(*type, _GSC_DBL); + (*_dDesImp)(_src, dDesSel, address, type, &_cursor, nil); + return; + + default: + [NSException raise: NSInternalInconsistencyException + format: @"read unknown type info - %d", info]; + } + + /* + * We fall through to here only when we have to decode a value + * whose natural size on this system is not the same as on the + * machine on which the archive was created. + */ + + /* + * First, we read the data and convert it to the largest size + * this system can support. + */ + switch (info & _GSC_SIZE) + { + case _GSC_I16: /* Encoded as 16-bit */ + { + gsu16 val; + + (*_dDesImp)(_src, dDesSel, &val, @encode(gsu16), &_cursor, nil); + bigval = val; + break; + } + + case _GSC_I32: /* Encoded as 32-bit */ + { + gsu32 val; + + (*_dDesImp)(_src, dDesSel, &val, @encode(gsu32), &_cursor, nil); + bigval = val; + break; + } + + case _GSC_I64: /* Encoded as 64-bit */ + { + gsu64 val; + + (*_dDesImp)(_src, dDesSel, &val, @encode(gsu64), &_cursor, nil); +#if GS_HAVE_I64 + bigval = val; +#else + bigval = GSSwapBigI64ToHost(val); +#endif + break; + } + + default: /* A 128-bit value */ + { + gsu128 val; + + (*_dDesImp)(_src, dDesSel, &val, @encode(gsu128), &_cursor, nil); +#if GS_HAVE_I128 + bigval = val; +#else + val = GSSwapBigI128ToHost(val); +#if GS_HAVE_I64 + bigval = *(gsu64*)&val; +#else + bigval = *(gsu32*)&val; +#endif +#endif + break; + } + } + +/* + * Now we copy from the 'bigval' to the destination location. + */ + switch (info & _GSC_MASK) + { + case _GSC_SHT: + *(short*)address = (short)bigval; + return; + case _GSC_USHT: + *(unsigned short*)address = (unsigned short)bigval; + return; + case _GSC_INT: + *(int*)address = (int)bigval; + return; + case _GSC_UINT: + *(unsigned int*)address = (unsigned int)bigval; + return; + case _GSC_LNG: + *(long*)address = (long)bigval; + return; + case _GSC_ULNG: + *(unsigned long*)address = (unsigned long)bigval; + return; +#ifdef _C_LNG_LNG + case _GSC_LNG_LNG: + *(long long*)address = (long long)bigval; + return; + case _GSC_ULNG_LNG: + *(unsigned long long*)address = (unsigned long long)bigval; + return; +#endif + default: + [NSException raise: NSInternalInconsistencyException + format: @"type/size information error"]; + } +} + +- (void) dispatch +{ + /* + * Get ready for re-use + * Make sure that we don't retain the connection - or it might never be + * released if it is keeping this coder in a cache. + */ + DESTROY(_conn); +} + +- (void) encodeArrayOfObjCType: (const char*)type + count: (unsigned)count + at: (const void*)buf +{ + unsigned i; + unsigned offset = 0; + unsigned size = objc_sizeof_type(type); + uchar info; + + switch (*type) + { + case _C_ID: info = _GSC_NONE; break; + case _C_CHR: info = _GSC_CHR; break; + case _C_UCHR: info = _GSC_UCHR; break; + case _C_SHT: info = _GSC_SHT | _GSC_S_SHT; break; + case _C_USHT: info = _GSC_USHT | _GSC_S_SHT; break; + case _C_INT: info = _GSC_INT | _GSC_S_INT; break; + case _C_UINT: info = _GSC_UINT | _GSC_S_INT; break; + case _C_LNG: info = _GSC_LNG | _GSC_S_LNG; break; + case _C_ULNG: info = _GSC_ULNG | _GSC_S_LNG; break; + case _C_LNG_LNG: info = _GSC_LNG_LNG | _GSC_S_LNG_LNG; break; + case _C_ULNG_LNG: info = _GSC_ULNG_LNG | _GSC_S_LNG_LNG; break; + case _C_FLT: info = _GSC_FLT; break; + case _C_DBL: info = _GSC_DBL; break; + default: info = _GSC_NONE; break; + } + + /* + * Simple types can be serialized immediately, more complex ones + * are dealt with by our [encodeValueOfObjCType:at:] method. + */ + if (info == _GSC_NONE) + { + if (_initialPass == NO) + { + (*_eTagImp)(_dst, eTagSel, _GSC_ARY_B); + (*_eSerImp)(_dst, eSerSel, &count, @encode(unsigned), nil); + } + for (i = 0; i < count; i++) + { + (*_eValImp)(self, eValSel, type, (char*)buf + offset); + offset += size; + } + } + else if (_initialPass == NO) + { + (*_eTagImp)(_dst, eTagSel, _GSC_ARY_B); + (*_eSerImp)(_dst, eSerSel, &count, @encode(unsigned), nil); + + (*_eTagImp)(_dst, eTagSel, info); + for (i = 0; i < count; i++) + { + (*_eSerImp)(_dst, eSerSel, (char*)buf + offset, type, nil); + offset += size; + } + } +} + +- (void) encodeBycopyObject: (id)anObj +{ + BOOL oldBycopy = _is_by_copy; + BOOL oldByref = _is_by_ref; + + _is_by_copy = YES; + _is_by_ref = NO; + (*_eObjImp)(self, eObjSel, anObj); + _is_by_copy = oldBycopy; + _is_by_ref = oldByref; +} + +- (void) encodeByrefObject: (id)anObj +{ + BOOL oldBycopy = _is_by_copy; + BOOL oldByref = _is_by_ref; + + _is_by_copy = NO; + _is_by_ref = YES; + (*_eObjImp)(self, eObjSel, anObj); + _is_by_copy = oldBycopy; + _is_by_ref = oldByref; +} + +- (void) encodeConditionalObject: (id)anObject +{ + if (_encodingRoot == NO) + { + [NSException raise: NSInvalidArgumentException + format: @"conditionally encoding without root object"]; + return; + } + + if (_initialPass) + { + GSIMapNode node; + + /* + * Conditionally encoding 'nil' is a no-op. + */ + if (anObject == nil) + { + return; + } + + /* + * If we have already conditionally encoded this object, we can + * ignore it this time. + */ + node = GSIMapNodeForKey(_cIdMap, (GSIMapKey)anObject); + if (node != 0) + { + return; + } + + /* + * If we have unconditionally encoded this object, we can ignore + * it now. + */ + node = GSIMapNodeForKey(_uIdMap, (GSIMapKey)anObject); + if (node != 0) + { + return; + } + + GSIMapAddPair(_cIdMap, (GSIMapKey)anObject, (GSIMapVal)0); + } + else if (anObject == nil) + { + (*_eObjImp)(self, eObjSel, nil); + } + else + { + GSIMapNode node; + + node = GSIMapNodeForKey(_cIdMap, (GSIMapKey)anObject); + if (node != 0) + { + (*_eObjImp)(self, eObjSel, nil); + } + else + { + (*_eObjImp)(self, eObjSel, anObject); + } + } +} + +/* + * When asked to encode a data object, we add the object to the components + * array, and simply record the array index, so the corresponding decode + * method can tell which component to use. + */ +- (void) encodeDataObject: (NSData*)anObject +{ + int pos; + + if (anObject == nil) + { + pos = -1; + } + else if ([anObject length] == 0) + { + pos = -2; + } + else + { + pos = (int)[_comp count]; + [_comp addObject: anObject]; + } + [self encodeValueOfObjCType: @encode(int) at: &pos]; +} + +- (void) encodeObject: (id)anObject +{ + if (anObject == nil) + { + if (_initialPass == NO) + { + /* + * Special case - encode a nil pointer as a crossref of zero. + */ + (*_eTagImp)(_dst, eTagSel, _GSC_ID | _GSC_XREF, _GSC_X_0); + } + } + else if (fastIsInstance(anObject) == NO) + { + /* + * If the object we have been given is actually a class, + * we encode it as a class instead. + */ + (*_eValImp)(self, eValSel, @encode(Class), &anObject); + } + else + { + GSIMapNode node; + + /* + * See if the object has already been encoded. + */ + node = GSIMapNodeForKey(_uIdMap, (GSIMapKey)anObject); + + if (_initialPass) + { + if (node == 0) + { + /* + * Remove object from map of conditionally encoded objects + * and add it to the map of unconditionay encoded ones. + */ + GSIMapRemoveKey(_cIdMap, (GSIMapKey)anObject); + GSIMapAddPair(_uIdMap, (GSIMapKey)anObject, (GSIMapVal)0); + [anObject encodeWithCoder: self]; + } + return; + } + + if (node == 0 || node->value.uint == 0) + { + Class cls; + id obj; + + if (node == 0) + { + node = GSIMapAddPair(_uIdMap, + (GSIMapKey)anObject, (GSIMapVal)++_xRefO); + } + else + { + node->value.uint = ++_xRefO; + } + + obj = [anObject replacementObjectForPortCoder: self]; + cls = [obj classForPortCoder]; + + (*_xRefImp)(_dst, xRefSel, _GSC_ID, node->value.uint); + (*_eValImp)(self, eValSel, @encode(Class), &cls); + [obj encodeWithCoder: self]; + } + else + { + (*_xRefImp)(_dst, xRefSel, _GSC_ID | _GSC_XREF, node->value.uint); + } + } +} + +/* + * When asked to encode a port object, we add the object to the components + * array, and simply record the array index, so the corresponding decode + * method can tell which component to use. + */ +- (void) encodePortObject: (NSPort*)anObject +{ + unsigned pos = [_comp count]; + + [_comp addObject: anObject]; + [self encodeValueOfObjCType: @encode(unsigned) at: &pos]; +} + +- (void) encodeRootObject: (id)rootObject +{ + if (_encodingRoot) + { + [NSException raise: NSInvalidArgumentException + format: @"encoding root object more than once"]; + } + + _encodingRoot = YES; + + /* + * First pass - find conditional objects. + */ + _initialPass = YES; + (*_eObjImp)(self, eObjSel, rootObject); + + /* + * Second pass - write archive. + */ + _initialPass = NO; + (*_eObjImp)(self, eObjSel, rootObject); + + /* + * Write sizes of crossref arrays to head of archive. + */ + [self _serializeHeaderAt: _cursor + version: [self systemVersion] + classes: _clsMap->nodeCount + objects: _uIdMap->nodeCount + pointers: _ptrMap->nodeCount]; + + _encodingRoot = NO; +} + +- (void) encodeValueOfObjCType: (const char*)type + at: (const void*)buf +{ + switch (*type) + { + case _C_ID: + (*_eObjImp)(self, eObjSel, *(void**)buf); + return; + + case _C_ARY_B: + { + int count = atoi(++type); + + while (isdigit(*type)) + { + type++; + } + + if (_initialPass == NO) + { + (*_eTagImp)(_dst, eTagSel, _GSC_ARY_B); + } + + [self encodeArrayOfObjCType: type count: count at: buf]; + } + return; + + case _C_STRUCT_B: + { + int offset = 0; + + if (_initialPass == NO) + { + (*_eTagImp)(_dst, eTagSel, _GSC_STRUCT_B); + } + + while (*type != _C_STRUCT_E && *type++ != '='); /* skip "=" */ + + for (;;) + { + (*_eValImp)(self, eValSel, type, (char*)buf + offset); + offset += objc_sizeof_type(type); + type = objc_skip_typespec(type); + if (*type == _C_STRUCT_E) + { + break; + } + else + { + int align = objc_alignof_type(type); + int rem = offset % align; + + if (rem != 0) + { + offset += align - rem; + } + } + } + } + return; + + case _C_PTR: + if (*(void**)buf == 0) + { + if (_initialPass == NO) + { + /* + * Special case - a nul pointer gets an xref of zero + */ + (*_eTagImp)(_dst, eTagSel, _GSC_PTR | _GSC_XREF | _GSC_X_0); + } + } + else + { + GSIMapNode node; + + node = GSIMapNodeForKey(_ptrMap, (GSIMapKey)*(void**)buf); + if (_initialPass == YES) + { + /* + * First pass - add pointer to map and encode item pointed + * to in case it is a conditionally encoded object. + */ + if (node == 0) + { + GSIMapAddPair(_ptrMap, + (GSIMapKey)*(void**)buf, (GSIMapVal)0); + type++; + buf = *(char**)buf; + (*_eValImp)(self, eValSel, type, buf); + } + } + else if (node == 0 || node->value.uint == 0) + { + /* + * Second pass, unwritten pointer - write it. + */ + if (node == 0) + { + node = GSIMapAddPair(_ptrMap, + (GSIMapKey)*(void**)buf, (GSIMapVal)++_xRefP); + } + else + { + node->value.uint = ++_xRefP; + } + (*_xRefImp)(_dst, xRefSel, _GSC_PTR, node->value.uint); + type++; + buf = *(char**)buf; + (*_eValImp)(self, eValSel, type, buf); + } + else + { + /* + * Second pass, write a cross-reference number. + */ + (*_xRefImp)(_dst, xRefSel, _GSC_PTR|_GSC_XREF, + node->value.uint); + } + } + return; + + default: /* Types that can be ignored in first pass. */ + if (_initialPass) + { + return; + } + break; + } + + switch (*type) + { + case _C_CLASS: + if (*(Class*)buf == 0) + { + /* + * Special case - a nul pointer gets an xref of zero + */ + (*_eTagImp)(_dst, eTagSel, _GSC_CLASS | _GSC_XREF | _GSC_X_0); + } + else + { + Class c = *(Class*)buf; + GSIMapNode node; + BOOL done = NO; + + node = GSIMapNodeForKey(_clsMap, (GSIMapKey)(void*)c); + + if (node != 0) + { + (*_xRefImp)(_dst, xRefSel, _GSC_CLASS | _GSC_XREF, + node->value.uint); + return; + } + while (done == NO) + { + int tmp = fastClassVersion(c); + unsigned version = tmp; + Class s = fastSuper(c); + + if (tmp < 0) + { + [NSException raise: NSInternalInconsistencyException + format: @"negative class version"]; + } + node = GSIMapAddPair(_clsMap, + (GSIMapKey)(void*)c, (GSIMapVal)++_xRefC); + /* + * Encode tag and crossref number. + */ + (*_xRefImp)(_dst, xRefSel, _GSC_CLASS, node->value.uint); + /* + * Encode class, and version. + */ + (*_eSerImp)(_dst, eSerSel, &c, @encode(Class), nil); + (*_eSerImp)(_dst, eSerSel, &version, @encode(unsigned), nil); + /* + * If we have a super class that has not been encoded, + * we must loop round to encode it here so that its + * version information will be available when objects + * of its subclasses are decoded and call + * [super initWithCoder:ccc] + */ + if (s == c || s == 0 + || GSIMapNodeForKey(_clsMap, (GSIMapKey)(void*)s) != 0) + { + done = YES; + } + else + { + c = s; + } + } + /* + * Encode an empty tag to terminate the list of classes. + */ + (*_eTagImp)(_dst, eTagSel, _GSC_NONE); + } + return; + + case _C_SEL: + if (*(SEL*)buf == 0) + { + /* + * Special case - a nul pointer gets an xref of zero + */ + (*_eTagImp)(_dst, eTagSel, _GSC_SEL | _GSC_XREF | _GSC_X_0); + } + else + { + SEL s = *(SEL*)buf; + GSIMapNode node = GSIMapNodeForKey(_ptrMap, (GSIMapKey)(void*)s); + + if (node == 0) + { + node = GSIMapAddPair(_ptrMap, + (GSIMapKey)(void*)s, (GSIMapVal)++_xRefP); + (*_xRefImp)(_dst, xRefSel, _GSC_SEL, node->value.uint); + /* + * Encode selector. + */ + (*_eSerImp)(_dst, eSerSel, buf, @encode(SEL), nil); + } + else + { + (*_xRefImp)(_dst, xRefSel, _GSC_SEL|_GSC_XREF, + node->value.uint); + } + } + return; + + case _C_CHARPTR: + if (*(char**)buf == 0) + { + /* + * Special case - a nul pointer gets an xref of zero + */ + (*_eTagImp)(_dst, eTagSel, _GSC_CHARPTR | _GSC_XREF | _GSC_X_0); + } + else + { + GSIMapNode node; + + node = GSIMapNodeForKey(_ptrMap, (GSIMapKey)*(char**)buf); + if (node == 0) + { + node = GSIMapAddPair(_ptrMap, + (GSIMapKey)*(char**)buf, (GSIMapVal)++_xRefP); + (*_xRefImp)(_dst, xRefSel, _GSC_CHARPTR, node->value.uint); + (*_eSerImp)(_dst, eSerSel, buf, type, nil); + } + else + { + (*_xRefImp)(_dst, xRefSel, _GSC_CHARPTR|_GSC_XREF, + node->value.uint); + } + } + return; + + case _C_CHR: + (*_eTagImp)(_dst, eTagSel, _GSC_CHR); + (*_eSerImp)(_dst, eSerSel, (void*)buf, @encode(char), nil); + return; + + case _C_UCHR: + (*_eTagImp)(_dst, eTagSel, _GSC_UCHR); + (*_eSerImp)(_dst, eSerSel, (void*)buf, @encode(unsigned char), nil); + return; + + case _C_SHT: + (*_eTagImp)(_dst, eTagSel, _GSC_SHT | _GSC_S_SHT); + (*_eSerImp)(_dst, eSerSel, (void*)buf, @encode(short), nil); + return; + + case _C_USHT: + (*_eTagImp)(_dst, eTagSel, _GSC_USHT | _GSC_S_SHT); + (*_eSerImp)(_dst, eSerSel, (void*)buf, @encode(unsigned short), nil); + return; + + case _C_INT: + (*_eTagImp)(_dst, eTagSel, _GSC_INT | _GSC_S_INT); + (*_eSerImp)(_dst, eSerSel, (void*)buf, @encode(int), nil); + return; + + case _C_UINT: + (*_eTagImp)(_dst, eTagSel, _GSC_UINT | _GSC_S_INT); + (*_eSerImp)(_dst, eSerSel, (void*)buf, @encode(unsigned int), nil); + return; + + case _C_LNG: + (*_eTagImp)(_dst, eTagSel, _GSC_LNG | _GSC_S_LNG); + (*_eSerImp)(_dst, eSerSel, (void*)buf, @encode(long), nil); + return; + + case _C_ULNG: + (*_eTagImp)(_dst, eTagSel, _GSC_ULNG | _GSC_S_LNG); + (*_eSerImp)(_dst, eSerSel, (void*)buf, @encode(unsigned long), nil); + return; + + case _C_LNG_LNG: + (*_eTagImp)(_dst, eTagSel, _GSC_LNG_LNG | _GSC_S_LNG_LNG); + (*_eSerImp)(_dst, eSerSel, (void*)buf, @encode(long long), nil); + return; + + case _C_ULNG_LNG: + (*_eTagImp)(_dst, eTagSel, _GSC_ULNG_LNG | _GSC_S_LNG_LNG); + (*_eSerImp)(_dst, eSerSel, (void*)buf, @encode(unsigned long long), + nil); + return; + + case _C_FLT: + (*_eTagImp)(_dst, eTagSel, _GSC_FLT); + (*_eSerImp)(_dst, eSerSel, (void*)buf, @encode(float), nil); + return; + + case _C_DBL: + (*_eTagImp)(_dst, eTagSel, _GSC_DBL); + (*_eSerImp)(_dst, eSerSel, (void*)buf, @encode(double), nil); + return; + + case _C_VOID: + [NSException raise: NSInvalidArgumentException + format: @"can't encode void item"]; + + default: + [NSException raise: NSInvalidArgumentException + format: @"item with unknown type - %s", type]; + } +} + +- (id) initWithReceivePort: (NSPort*)recv + sendPort: (NSPort*)send + components: (NSArray*)comp +{ + BOOL firstTime; + + _conn = RETAIN([connectionClass connectionWithReceivePort: recv + sendPort: send]); + if (_comp == nil) + { + firstTime = YES; + _version = [super systemVersion]; + _zone = NSDefaultMallocZone(); + } + else + { + NSAssert(recv == [_conn receivePort] && send == [_conn sendPort], + NSInvalidArgumentException); + /* + * Re-initialising - destroy old components. + */ + firstTime = NO; + } + + if (comp == nil) + { + NS_DURING + { + _encodingRoot = NO; + _initialPass = NO; + _xRefC = 0; + _xRefO = 0; + _xRefP = 0; + + _cursor = [send reservedSpaceLength]; + if (firstTime == YES) + { + /* + * Set up mutable data object to encode into - reserve space at + * the start for use by the port when the encoded data is sent. + * Make the data item the first component of the array. + */ + _comp = [mutableArrayClass new]; + _dst = [mutableDataClass allocWithZone: _zone]; + _dst = [_dst initWithLength: _cursor]; + [_comp addObject: _dst]; + + /* + * Cache method implementations for writing into data object etc + */ + _eObjImp = [self methodForSelector: eObjSel]; + _eValImp = [self methodForSelector: eValSel]; + + /* + * Set up map tables. + */ + _clsMap + = (GSIMapTable)NSZoneMalloc(_zone, sizeof(GSIMapTable_t)*4); + _cIdMap = &_clsMap[1]; + _uIdMap = &_clsMap[2]; + _ptrMap = &_clsMap[3]; + GSIMapInitWithZoneAndCapacity(_clsMap, _zone, 100); + GSIMapInitWithZoneAndCapacity(_cIdMap, _zone, 10); + GSIMapInitWithZoneAndCapacity(_uIdMap, _zone, 200); + GSIMapInitWithZoneAndCapacity(_ptrMap, _zone, 100); + } + else + { + /* + * If re-initialising, we need to empty the old stuff. + * NB. Our _dst object may have been removed from the _comp + * array elsewhere, so we empty the _comp array and then re-add + * _dst + */ + [_comp removeAllObjects]; + [_comp addObject: _dst]; + [_dst setLength: _cursor]; + GSIMapCleanMap(_clsMap); + GSIMapCleanMap(_cIdMap); + GSIMapCleanMap(_uIdMap); + GSIMapCleanMap(_ptrMap); + } + + /* + * Write dummy header + */ + [self _serializeHeaderAt: _cursor + version: 0 + classes: 0 + objects: 0 + pointers: 0]; + } + NS_HANDLER + { + NSLog(@"Exception setting up port coder for encoding - %@", + localException); + DESTROY(self); + } + NS_ENDHANDLER + } + else + { + RELEASE(_comp); + _comp = [comp mutableCopy]; + NS_DURING + { + unsigned sizeC; + unsigned sizeO; + unsigned sizeP; + + if (firstTime == YES) + { + _dValImp = [self methodForSelector: dValSel]; + } + _src = [_comp objectAtIndex: 0]; + _dDesImp = [_src methodForSelector: dDesSel]; + _dTagImp = (void (*)(id, SEL, unsigned char*, unsigned*, unsigned*)) + [_src methodForSelector: dTagSel]; + + /* + * _cInfo is a dictionary of objects for keeping track of the + * version numbers that the classes were encoded with. + */ + if (firstTime == NO) + { + [_cInfo removeAllObjects]; + } + + /* + * Read header including version and crossref table sizes. + */ + _cursor = 0; + [self _deserializeHeaderAt: &_cursor + version: &_version + classes: &sizeC + objects: &sizeO + pointers: &sizeP]; + + /* + * Allocate and initialise arrays to build crossref maps in. + */ + if (firstTime == YES) + { + _clsAry = NSZoneMalloc(_zone, sizeof(GSIArray_t)*3); + _objAry = &_clsAry[1]; + _ptrAry = &_clsAry[2]; + GSIArrayInitWithZoneAndCapacity(_clsAry, _zone, sizeC); + GSIArrayInitWithZoneAndCapacity(_objAry, _zone, sizeO); + GSIArrayInitWithZoneAndCapacity(_ptrAry, _zone, sizeP); + } + else + { + unsigned count = GSIArrayCount(_clsAry); + + while (count-- > 0) + { + RELEASE(GSIArrayItemAtIndex(_clsAry, count).obj); + } + GSIArrayRemoveAllItems(_clsAry); + GSIArrayRemoveAllItems(_objAry); + GSIArrayRemoveAllItems(_ptrAry); + } + GSIArrayAddItem(_clsAry, (GSIArrayItem)nil); + GSIArrayAddItem(_objAry, (GSIArrayItem)nil); + GSIArrayAddItem(_ptrAry, (GSIArrayItem)0); + } + NS_HANDLER + { + NSLog(@"Exception setting up port coder for decoding - %@", + localException); + DESTROY(self); + } + NS_ENDHANDLER + } + return self; +} + +- (BOOL) isBycopy +{ + return _is_by_copy; +} + +- (BOOL) isByref +{ + return _is_by_ref; +} + +- (NSZone*) objectZone +{ + return _zone; +} + +- (void) setObjectZone: (NSZone*)aZone +{ + _zone = aZone; +} + +- (unsigned) systemVersion +{ + return _version; +} + +- (unsigned) versionForClassName: (NSString*)className +{ + GSClassInfo *info = nil; + unsigned version = NSNotFound; + unsigned count = GSIArrayCount(_clsAry); + + /* + * Lazy ... we construct a dictionary of all the class information in + * the request the first time that class version info is asked for. + */ + if (_cInfo == nil) + { + _cInfo = [[mutableDictionaryClass alloc] initWithCapacity: count]; + } + if ([_cInfo count] == 0) + { + while (count-- > 0) + { + info = GSIArrayItemAtIndex(_clsAry, count).obj; + [_cInfo setObject: info forKey: NSStringFromClass(info->class)]; + } + } + info = [_cInfo objectForKey: className]; + if (info != nil) + { + version = info->version; + } + return version; +} + +@end + + + +@implementation NSPortCoder (Private) + +- (NSMutableArray*) _components +{ + return _comp; +} + +@end + +@implementation NSPortCoder (Headers) + +- (void) _deserializeHeaderAt: (unsigned*)pos + version: (unsigned*)v + classes: (unsigned*)c + objects: (unsigned*)o + pointers: (unsigned*)p +{ + unsigned plen = strlen(PREFIX); + unsigned size = plen+36; + char header[size+1]; + + [_src getBytes: header range: NSMakeRange(*pos, size)]; + *pos += size; + header[size] = '\0'; + if (strncmp(header, PREFIX, plen) != 0) + { + [NSException raise: NSInternalInconsistencyException + format: @"Archive has wrong prefix"]; + } + if (sscanf(&header[plen], "%x:%x:%x:%x:", v, c, o, p) != 4) + { + [NSException raise: NSInternalInconsistencyException + format: @"Archive has wrong prefix"]; + } +} + +- (void) _serializeHeaderAt: (unsigned)locationInData + version: (unsigned)v + classes: (unsigned)cc + objects: (unsigned)oc + pointers: (unsigned)pc +{ + unsigned headerLength = strlen(PREFIX)+36; + char header[headerLength+1]; + unsigned dataLength = [_dst length]; + + sprintf(header, "%s%08x:%08x:%08x:%08x:", PREFIX, v, cc, oc, pc); + + if (locationInData + headerLength <= dataLength) + { + [_dst replaceBytesInRange: NSMakeRange(locationInData, headerLength) + withBytes: header]; + } + else if (locationInData == dataLength) + { + [_dst appendBytes: header length: headerLength]; + } + else + { + [NSException raise: NSInternalInconsistencyException + format: @"serializeHeader:at: bad location"]; + } +} + +@end + +#else +/* Implementation of NSPortCoder object for remote messaging + Copyright (C) 1997 Free Software Foundation, Inc. + + This implementation for OPENSTEP conformance written by + Richard Frith-Macdonald + Created: August 1997 + + based on original code - + + Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: July 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_SIZE 256 + +#define PORT_CODER_FORMAT_VERSION ((((GNUSTEP_BASE_MAJOR_VERSION * 100) + \ + GNUSTEP_BASE_MINOR_VERSION) * 100) + GNUSTEP_BASE_SUBMINOR_VERSION) + +static BOOL debug_connected_coder = NO; + +/* + * The PortEncoder class is essentially the old ConnectedEncoder class + * with a name change. + * It uses the OPENSTEP method [-classForPortCoder] to ask an object + * what class to encode. + */ +@interface PortEncoder : Encoder +{ + NSConnection *connection; + unsigned sequence_number; + int identifier; + BOOL _is_by_copy; + BOOL _is_by_ref; +} + ++ newForWritingWithConnection: (NSConnection*)c + sequenceNumber: (int)n + identifier: (int)i; +- (void) dismiss; +- (NSConnection*) connection; +- (unsigned) sequenceNumber; +- (int) identifier; +@end + +@implementation PortEncoder + +- _initForWritingWithConnection: (NSConnection*)c + sequenceNumber: (int)n + identifier: (int)i +{ + OutPacket* packet = [[[(OutPort*)[c sendPort] outPacketClass] alloc] + initForSendingWithCapacity: DEFAULT_SIZE + replyInPort: [c receivePort]]; + [super initForWritingToStream: packet]; + [packet release]; + connection = c; + sequence_number = n; + identifier = i; + [self encodeValueOfCType: @encode(typeof(sequence_number)) + at: &sequence_number + withName: @"PortCoder sequence number"]; + [self encodeValueOfCType: @encode(typeof(identifier)) + at: &identifier + withName: @"PortCoder identifier"]; + return self; +} + ++ newForWritingWithConnection: (NSConnection*)c + sequenceNumber: (int)n + identifier: (int)i +{ + /* Export this method and not the -init... method because eventually + we may do some caching of old PortEncoder's to speed things up. */ + return [[self alloc] _initForWritingWithConnection: c + sequenceNumber: n + identifier: i]; +} + +- (void) dismiss +{ + id packet = [cstream stream]; + NS_DURING + { + [(OutPort*)[connection sendPort] sendPacket: packet + timeout: [connection requestTimeout]]; + } + NS_HANDLER + { + if (debug_connected_coder) + fprintf(stderr, "dismiss 0x%x: #=%d i=%d write failed - %s\n", + (unsigned)self, sequence_number, identifier, + [[localException reason] cString]); + if ([[connection sendPort] isValid]) + [[connection sendPort] invalidate]; + } + NS_ENDHANDLER + if (debug_connected_coder) + fprintf(stderr, "dismiss 0x%x: #=%d i=%d %d\n", + (unsigned)self, sequence_number, identifier, + [packet streamEofPosition]); + [self release]; +} + + +/* Access to ivars. */ + +- (int) identifier +{ + return identifier; +} + +- (NSConnection*) connection +{ + return connection; +} + +- (BOOL) isBycopy +{ + return _is_by_copy; +} + +- (BOOL) isByref +{ + return _is_by_ref; +} + +- (unsigned) sequenceNumber +{ + return sequence_number; +} + + +/* + * These three methods are called by Coder's designated object encoder when + * an object is to be sent over the wire with/without bycopy/byref. + * We make sure that if the object asks us whether it is to be sent bycopy + * or byref it is told the right thing. + */ +- (void) _doEncodeObject: anObj +{ + id obj; + Class cls; + + obj = [anObj replacementObjectForPortCoder: (NSPortCoder*)self]; + cls = [obj classForPortCoder]; + [self encodeClass: cls]; + [obj encodeWithCoder: (NSCoder*)self]; +} + +- (void) _doEncodeBycopyObject: anObj +{ + BOOL oldBycopy = _is_by_copy; + BOOL oldByref = _is_by_ref; + id obj; + Class cls; + + _is_by_copy = YES; + _is_by_ref = NO; + obj = [anObj replacementObjectForPortCoder: (NSPortCoder*)self]; + cls = [obj classForPortCoder]; + [self encodeClass: cls]; + [obj encodeWithCoder: (NSCoder*)self]; + _is_by_copy = oldBycopy; + _is_by_ref = oldByref; +} + +- (void) _doEncodeByrefObject: anObj +{ + BOOL oldBycopy = _is_by_copy; + BOOL oldByref = _is_by_ref; + id obj; + Class cls; + + _is_by_copy = NO; + _is_by_ref = YES; + obj = [anObj replacementObjectForPortCoder: (NSPortCoder*)self]; + cls = [obj classForPortCoder]; + [self encodeClass: cls]; + [obj encodeWithCoder: (NSCoder*)self]; + _is_by_copy = oldBycopy; + _is_by_ref = oldByref; +} + +- (void) writeSignature +{ + return; +} + +- (void) encodeDataObject: (NSData*)anObject +{ + unsigned l = [anObject length]; + + [self encodeValueOfObjCType: @encode(unsigned) at: &l]; + if (l) + { + const void *b = [anObject bytes]; + + [self encodeArrayOfObjCType: @encode(unsigned char) + count: l + at: b]; + } +} +@end + + + +/* + * The PortDecoder class is essentially the old ConnectedDecoder class + * with a name change. + */ +@interface PortDecoder : Decoder +{ + NSConnection *connection; + unsigned sequence_number; + int identifier; +} + ++ newDecodingWithPacket: (InPacket*)packet + connection: (NSConnection*)c; ++ newDecodingWithConnection: (NSConnection*)c + timeout: (int) timeout; +- (void) dismiss; +- (NSConnection*) connection; +- (unsigned) sequenceNumber; +- (int) identifier; +- (NSPort*) replyPort; +@end + +@implementation PortDecoder + ++ (void) readSignatureFromCStream: (id ) cs + getClassname: (char *) name + formatVersion: (int*) version +{ + const char *classname = class_get_class_name (self); + strcpy (name, classname); + *version = PORT_CODER_FORMAT_VERSION; +} + ++ newDecodingWithConnection: (NSConnection*)c + timeout: (int) timeout +{ + PortDecoder *cd; + id in_port; + id packet; + id reply_port; + + /* Try to get a packet. */ + in_port = [c receivePort]; + packet = [in_port receivePacketWithTimeout: timeout]; + if (!packet) + return nil; /* timeout */ + + /* Create the new PortDecoder */ + cd = [self newReadingFromStream: packet]; + [packet release]; + reply_port = [packet replyPort]; + cd->connection = [NSConnection newForInPort: in_port + outPort: reply_port + ancestorConnection: c]; + + /* Decode the PortDecoder's ivars. */ + [cd decodeValueOfCType: @encode(typeof(cd->sequence_number)) + at: &(cd->sequence_number) + withName: NULL]; + [cd decodeValueOfCType: @encode(typeof(cd->identifier)) + at: &(cd->identifier) + withName: NULL]; + + if (debug_connected_coder) + fprintf(stderr, "newDecoding #=%d id=%d\n", + cd->sequence_number, cd->identifier); + return cd; +} + ++ newDecodingWithPacket: (InPacket*)packet + connection: (NSConnection*)c +{ + PortDecoder *cd; + id in_port; + id reply_port; + + in_port = [c receivePort]; + + /* Create the new PortDecoder */ + cd = [self newReadingFromStream: packet]; + [packet release]; + reply_port = [packet replyOutPort]; + cd->connection = [NSConnection newForInPort: in_port + outPort: reply_port + ancestorConnection: c]; + + /* Decode the PortDecoder's ivars. */ + [cd decodeValueOfCType: @encode(typeof(cd->sequence_number)) + at: &(cd->sequence_number) + withName: NULL]; + [cd decodeValueOfCType: @encode(typeof(cd->identifier)) + at: &(cd->identifier) + withName: NULL]; + + if (debug_connected_coder) + fprintf(stderr, "newDecoding #=%d id=%d\n", + cd->sequence_number, cd->identifier); + return cd; +} + + +/* Access to ivars. */ + +- (int) identifier +{ + return identifier; +} + +- (NSConnection*) connection +{ + return connection; +} + +- (NSPort*) replyPort +{ + return (NSPort*)[(id)[cstream stream] replyPort]; +} + +- (unsigned) sequenceNumber +{ + return sequence_number; +} + +- (void) dealloc +{ + [connection release]; + [super dealloc]; +} + +- (void) dismiss +{ + [self release]; +} + +- (NSData*) decodeDataObject +{ + unsigned l; + + [self decodeValueOfObjCType: @encode(unsigned) at: &l]; + if (l) + { + void *b; + NSData *d; + NSZone *z; + +#if GS_WITH_GC + z = GSAtomicMallocZone(); +#else + z = NSDefaultMallocZone(); +#endif + b = NSZoneMalloc(z, l); + [self decodeArrayOfObjCType: @encode(unsigned char) + count: l + at: b]; + d = [[NSData alloc] initWithBytesNoCopy: b length: l fromZone: z]; + IF_NO_GC(AUTORELEASE(d)); + return d; + } + return [NSData data]; +} + +@end + + + +/* + * The NSPortCoder class is an abstract class which is used to create + * instances of PortEncoder or PortDecoder depending on what factory + * method is used. + */ +@implementation NSPortCoder + ++ newDecodingWithConnection: (NSConnection*)c + timeout: (int) timeout +{ + return [PortDecoder newDecodingWithConnection:c timeout:timeout]; +} + ++ newDecodingWithPacket: (InPacket*)packet + connection: (NSConnection*)c +{ + return [PortDecoder newDecodingWithPacket:packet connection:c]; +} + ++ newForWritingWithConnection: (NSConnection*)c + sequenceNumber: (int)n + identifier: (int)i +{ + return [[PortEncoder alloc] _initForWritingWithConnection: c + sequenceNumber: n + identifier: i]; +} + +- allocWithZone: (NSZone*)z +{ + [self subclassResponsibility:_cmd]; + return nil; +} + +- (NSConnection*) connection +{ + [self subclassResponsibility:_cmd]; + return nil; +} + +- (NSPort*) decodePortObject +{ + [self subclassResponsibility:_cmd]; + return nil; +} + +- (void) dismiss +{ + [self subclassResponsibility:_cmd]; +} + +- (void) encodePortObject: (NSPort*)aPort +{ + [self subclassResponsibility:_cmd]; +} + +- (int) identifier +{ + [self subclassResponsibility:_cmd]; + return 0; +} + +- (BOOL) isBycopy +{ + [self subclassResponsibility:_cmd]; + return NO; +} + +- (BOOL) isByref +{ + [self subclassResponsibility:_cmd]; + return NO; +} + +- (NSPort*) replyPort +{ + [self subclassResponsibility:_cmd]; + return nil; +} + +- (unsigned) sequenceNumber +{ + [self subclassResponsibility:_cmd]; + return 0; +} + +@end diff --git a/Old/OrderedCollecting.h b/Old/OrderedCollecting.h new file mode 100644 index 000000000..3b5c3bb7b --- /dev/null +++ b/Old/OrderedCollecting.h @@ -0,0 +1,65 @@ +/* Protocol for Objective-C objects that hold elements, user gets to set order + Copyright (C) 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: Feb 1996 + + 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. +*/ + +/* The protocol inherits from the + protocol. + + The protocol defines the interface to a + collection of elements that are accessible by a key that is an index, + where the indeces in a collection are a contiguous series of unsigned + integers beginning at 0. This is the root of the protocol heirarchy + for all collections that hold their elements in some order. Elements + may be accessed, inserted, replaced and removed by their index. +*/ + +#ifndef __OrderedCollecting_h_GNUSTEP_BASE_INCLUDE +#define __OrderedCollecting_h_GNUSTEP_BASE_INCLUDE + +#include + +@protocol OrderedCollecting + +// ADDING; +- (void) insertObject: newObject atIndex: (unsigned)index; +- (void) insertObject: newObject before: oldObject; +- (void) insertObject: newObject after: oldObject; +- (void) insertContentsOf: (id )aCollection + atIndex: (unsigned)index; +- (void) appendObject: newObject; +- (void) prependObject: newObject; +- (void) appendContentsOf: (id )aCollection; +- (void) prependContentsOf: (id )aCollection; + +// SWAPPING AND SORTING +- (void) swapAtIndeces: (unsigned)index1 : (unsigned)index2; +- (void) sortContents; + +// REPLACING; +- (void) replaceRange: (IndexRange)aRange + with: (id )aCollection; +- replaceRange: (IndexRange)aRange + using: (id )aCollection; + +@end + +#endif /* __OrderedCollecting_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/OrderedCollection.h b/Old/OrderedCollection.h new file mode 100644 index 000000000..709688002 --- /dev/null +++ b/Old/OrderedCollection.h @@ -0,0 +1,38 @@ +/* Interface for Objective-C Ordered Collection object. + Copyright (C) 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: February 1996 + + 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 __OrderedCollection_h_GNUSTEP_BASE_INCLUDE +#define __OrderedCollection_h_GNUSTEP_BASE_INCLUDE + +#include +#include + +@interface OrderedCollection : IndexedCollection +@end + + +/* Put this on category instead of class to avoid bogus complaint from gcc */ +@interface OrderedCollection (Protocol) +@end + +#endif /* __OrderedCollection_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/OrderedCollection.m b/Old/OrderedCollection.m new file mode 100644 index 000000000..121d277d5 --- /dev/null +++ b/Old/OrderedCollection.m @@ -0,0 +1,265 @@ +/* Implementation for Objective-C OrderedCollection object + Copyright (C) 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: Feb 1996 + + 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. +*/ + +#include +#include +#include +#include +#include +#include + + +@implementation OrderedCollection + + +// ADDING; + +- (void) insertObject: newObject atIndex: (unsigned)index +{ + [self subclassResponsibility: _cmd]; +} + +- (void) insertObject: newObject before: oldObject +{ + int i = [self indexOfObject: oldObject]; + [self insertObject: newObject atIndex: i]; +} + +- (void) insertObject: newObject after: oldObject +{ + int i = [self indexOfObject: oldObject]; + [self insertObject: newObject atIndex: i+1]; +} + +- (void) insertContentsOf: (id ) aCollection + atIndex: (unsigned)index +{ + [self notImplemented: _cmd]; +#if 0 + void doIt(elt e) + { + [self insertElement: e atIndex: index]; + } + if (aCollection == self) + [self safeWithElementsInReverseCall:doIt]; + else + { + if ([(id)aCollection respondsToSelector: + @selector(withElemetnsInReverseCall:)]) + [(id)aCollection withElementsInReverseCall:doIt]; + else + [aCollection withElementsCall:doIt]; + } +#endif +} + +- (void) appendObject: newObject +{ + [self insertObject: newObject atIndex: [self count]]; +} + +- (void) prependObject: newObject +{ + [self insertObject: newObject atIndex: 0]; +} + +- (void) appendContentsOf: (id ) aCollection +{ + id o; + + NSAssert(aCollection != self, NSInvalidArgumentException); + /* xxx Could be more efficient. */ + FOR_COLLECTION(aCollection, o) + { + [self appendObject: o]; + } + END_FOR_COLLECTION(aCollection); +} + +- (void) prependContentsOf: (id )aCollection +{ + id o; + + NSAssert(aCollection != self, NSInvalidArgumentException); + if ([(id)aCollection conformsTo: @protocol(IndexedCollecting)]) + { + FOR_INDEXED_COLLECTION_REVERSE(self, o) + { + [self prependObject: o]; + } + END_FOR_INDEXED_COLLECTION_REVERSE(self); + } + else + { + FOR_COLLECTION(self, o) + { + [self prependObject: o]; + } + END_FOR_COLLECTION(self); + } +} + + +// SWAPPING AND SORTING; + +- (void) swapAtIndeces: (unsigned)index1 : (unsigned)index2 +{ + id tmp = [self objectAtIndex:index1]; + [self replaceObjectAtIndex: index1 with: [self objectAtIndex: index2]]; + [self replaceObjectAtIndex: index2 with: tmp]; +} + +/* This could be hacked a bit to make it more efficient */ +- (void) quickSortContentsFromIndex: (unsigned)p + toIndex: (unsigned)r +{ + unsigned i ,j; + id x; + + if (p < r) + { + /* Partition */ + x = [self objectAtIndex:p]; + i = p - 1; + j = r + 1; + for (;;) + { + do + j = j - 1; + while ([[self objectAtIndex: j] compare: x] > 0); + do + i = i + 1; + while ([[self objectAtIndex: i] compare: x] < 0); + if (i < j) + [self swapAtIndeces: i : j]; + else + break; + } + /* Sort partitions */ + [self quickSortContentsFromIndex: p toIndex: j]; + [self quickSortContentsFromIndex: j+1 toIndex: r]; + } +} + +- (void) sortContents +{ + [self quickSortContentsFromIndex: 0 toIndex: [self count]-1]; +} + + +// REPLACING; + +- (void) replaceRange: (IndexRange)aRange + withCollection: (id )aCollection +{ + [self notImplemented: _cmd]; +} + +- (void) replaceRange: (IndexRange)aRange + usingCollection: (id )aCollection +{ + [self notImplemented: _cmd]; +} + +#if 0 +- replaceRange: (IndexRange)aRange + with: (id )aCollection +{ + CHECK_INDEX_RANGE_ERROR(aRange.location, [self count]); + CHECK_INDEX_RANGE_ERROR(aRange.location+aRange.length-1, [self count]); + [self removeRange:aRange]; + [self insertContentsOf:aCollection atIndex:aRange.location]; + return self; +} + +- replaceRange: (IndexRange)aRange + using: (id )aCollection +{ + int i; + void *state = [aCollection newEnumState]; + elt e; + + CHECK_INDEX_RANGE_ERROR(aRange.location, [self count]); + CHECK_INDEX_RANGE_ERROR(aRange.location+aRange.length-1, [self count]); + for (i = aRange.location; + i < aRange.location + aRange.length + && [aCollection getNextElement:&e withEnumState:&state]; + i++) + { + [self replaceElementAtIndex:i with:e]; + } + [aCollection freeEnumState:&state]; + return self; +} +#endif + + + +// OVERRIDE SOME COLLECTION METHODS; + +- (void) addObject: newObject +{ + [self appendObject: newObject]; +} + +- (void) addContentsOf: (id )aCollection +{ + [self appendContentsOf: aCollection]; +} + + +#if 0 +// OVERRIDE SOME KEYED COLLECTION METHODS; + +/* Semantics: You can "put" an element only at index "count" or less */ +- (void) putObject: newObject atIndex: (unsigned)index +{ + unsigned c = [self count]; + + if (index < c) + [self replaceObjectAtIndex: index withObject: newObject]; + else if (index == c) + [self appendObject: newObject]; + else + [NSException + raise: NSRangeException + format: @"in %s, can't put an element at index beyond [self count]"]; +} + +- putObject: newObject atKey: index +{ + return [self putObject: newObject atIndex: [index unsignedIntValue]]; +} +#endif + + +// OVERRIDE SOME INDEXED COLLECTION METHODS; + +/* Should be more efficiently overriden by some subclasses. */ +- (void) replaceObjectAtIndex: (unsigned)index withObject: newObject +{ + [self removeObjectAtIndex: index]; + [self insertObject: newObject atIndex: index]; +} + +@end diff --git a/Old/Ordering.h b/Old/Ordering.h new file mode 100644 index 000000000..ff4a5ee39 --- /dev/null +++ b/Old/Ordering.h @@ -0,0 +1,47 @@ +/* Protocol for Objective-C objects that can be ordered. + Copyright (C) 1993,1994 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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 __Ordering_h_GNUSTEP_BASE_INCLUDE +#define __Ordering_h_GNUSTEP_BASE_INCLUDE + +#include +#include + +@protocol Ordering + +- (int) compare: anObject; + +- (BOOL) greaterThan: anObject; +- (BOOL) greaterThanOrEqual: anObject; + +- (BOOL) lessThan: anObject; +- (BOOL) lessThanOrEqual: anObject; + +- (BOOL) between: firstObject and: secondObject; + +- maximum: anObject; +- minimum: anObject; + +@end + +#endif /* __Ordering_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/Port.h b/Old/Port.h new file mode 100644 index 000000000..5b63b7ba2 --- /dev/null +++ b/Old/Port.h @@ -0,0 +1,119 @@ +/* Interface for abstract superclass port for use with Connection + Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: July 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 __Port_h_GNUSTEP_BASE_INCLUDE +#define __Port_h_GNUSTEP_BASE_INCLUDE + +#include +#include +#include +#include +#include + +/* xxx Use something like this? */ +@protocol PacketSending +@end + +@interface Port : NSPort +{ +} +- (void) close; + ++ (Class) outPacketClass; +- (Class) outPacketClass; + +@end + + +@interface InPort : Port +{ + id _packet_invocation; +} + ++ newForReceiving; ++ newForReceivingFromRegisteredName: (NSString*)name; ++ newForReceivingFromRegisteredName: (NSString*)name fromPort: (int)port; + +/* Register/Unregister this port for input handling through RunLoop + RUN_LOOP in mode MODE. */ +- (void) addToRunLoop: run_loop forMode: (NSString*)mode; +- (void) removeFromRunLoop: run_loop forMode: (NSString*)mode; + +/* When a RunLoop is handling this InPort, and a new incoming + packet arrives, INVOCATION will be invoked with the new packet + as an argument. The INVOCATION is responsible for releasing + the packet. */ +- (void) setReceivedPacketInvocation: (id)invocation; + +/* An alternative to the above way for receiving packets from this port. + Get a packet from the net and return it. If no packet is received + within MILLISECONDS, then return nil. The caller is responsible + for releasing the packet. */ +- receivePacketWithTimeout: (int)milliseconds; + +@end + + +@interface OutPort : Port + ++ newForSendingToRegisteredName: (NSString*)name + onHost: (NSString*)hostname; +- (BOOL) sendPacket: packet timeout: (NSTimeInterval)t; + +@end + + +/* Objects for holding incoming/outgoing data to/from ports. */ + +@interface InPacket : MemoryStream +{ + id _receiving_in_port; + id _reply_out_port; +} + +- replyOutPort; +- receivingInPort; + +/* Do not call this method yourself; it is to be called by subclassers. + InPackets are created for you by the InPort object, and are + made available as the argument to the received packet invocation. */ +- initForReceivingWithCapacity: (unsigned)s + receivingInPort: ip + replyOutPort: op; + +@end + +@interface OutPacket : MemoryStream +{ + id _reply_in_port; +} + +- initForSendingWithCapacity: (unsigned)c + replyInPort: p; +- replyInPort; + ++ (unsigned) prefixSize; + +@end + +#endif /* __Port_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/Port.m b/Old/Port.m new file mode 100644 index 000000000..23be04b3c --- /dev/null +++ b/Old/Port.m @@ -0,0 +1,210 @@ +/* Implementation of abstract superclass port for use with Connection + Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: July 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. + */ + +#include +#include +#include /* for Coding protocol in Object category */ +#include +#include + +@implementation Port + +/* This is the designated initializer. */ +- init +{ + [super init]; + _is_valid = YES; + return self; +} + +- (void) close +{ + [self invalidate]; +} + ++ (Class) outPacketClass +{ + [self subclassResponsibility: _cmd]; + return nil; +} + +- (Class) outPacketClass +{ + [self subclassResponsibility: _cmd]; + return nil; +} + +- (Class) classForPortCoder +{ + /* Make sure that Connection's always send us bycopy, + i.e. as our own class, not a Proxy class. */ + return [self class]; +} +- replacementObjectForPortCoder: aRmc +{ + return self; +} + +- (void) encodeWithCoder: (id )anEncoder +{ + [super encodeWithCoder: anEncoder]; + /* xxx What else? */ +} + +- initWithCoder: (id )coder +{ + self = [super initWithCoder: coder]; + /* xxx What else? */ + return self; +} + +@end + + +@implementation InPort + +- init +{ + [super init]; + _packet_invocation = nil; + return self; +} + ++ newForReceivingFromRegisteredName: (NSString*)name fromPort: (int)port +{ + [self subclassResponsibility:_cmd]; + return nil; +} + ++ newForReceivingFromRegisteredName: (NSString*)name +{ + [self subclassResponsibility:_cmd]; + return nil; +} + ++ newForReceiving +{ + return [self newForReceivingFromRegisteredName: nil]; +} + +- receivePacketWithTimeout: (int)milliseconds +{ + [self subclassResponsibility:_cmd]; + return nil; +} + +- (void) setReceivedPacketInvocation: (id)invocation +{ + NSAssert(!_packet_invocation, NSInternalInconsistencyException); + _packet_invocation = invocation; +} + +- (void) addToRunLoop: run_loop forMode: (NSString*)mode +{ + [self subclassResponsibility:_cmd]; +} + +- (void) removeFromRunLoop: run_loop forMode: (NSString*)mode +{ + [self subclassResponsibility:_cmd]; +} + +@end + + +@implementation OutPort + ++ newForSendingToRegisteredName: (NSString*)name + onHost: (NSString*)hostname +{ + [self subclassResponsibility:_cmd]; + return nil; +} + +- (BOOL) sendPacket: packet timeout: (NSTimeInterval)t +{ + [self subclassResponsibility:_cmd]; + return NO; +} + +@end + + +@implementation InPacket + +/* The designated initializer. */ +- initForReceivingWithCapacity: (unsigned)c + receivingInPort: ip + replyOutPort: op +{ + self = [super initWithCapacity: c prefix: 0]; + if (self) + { + NSAssert([op isValid], NSInternalInconsistencyException); + NSAssert(!ip || [ip isValid], NSInternalInconsistencyException); + _reply_out_port = op; + _receiving_in_port = ip; + } + return self; +} + +- replyOutPort +{ + return _reply_out_port; +} + +- receivingInPort +{ + return _receiving_in_port; +} + +@end + + +@implementation OutPacket + +/* The designated initializer. */ +- initForSendingWithCapacity: (unsigned)c + replyInPort: ip +{ + self = [super initWithCapacity: c prefix: [[self class] prefixSize]]; + if (self) + { + NSAssert([ip isValid], NSInternalInconsistencyException); + _reply_in_port = ip; + } + return self; +} + ++ (unsigned) prefixSize +{ + return 0; +} + +- replyInPort +{ + return _reply_in_port; +} + +@end + diff --git a/Old/Queue.h b/Old/Queue.h new file mode 100644 index 000000000..beb6d8354 --- /dev/null +++ b/Old/Queue.h @@ -0,0 +1,36 @@ +/* Interface for Objective-C Queue object + Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: May 1993 + + 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 __Queue_h_GNUSTEP_BASE_INCLUDE +#define __Queue_h_GNUSTEP_BASE_INCLUDE + +#include + +@interface Queue : CircularArray + +- (void) enqueueObject: newObject; +- dequeueObject; + +@end + +#endif /* __Queue_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/Queue.m b/Old/Queue.m new file mode 100644 index 000000000..cb2dae34d --- /dev/null +++ b/Old/Queue.m @@ -0,0 +1,48 @@ +/* Implementation for Objective-C Queue object + Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: May 1993 + + 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. +*/ + +#include +#include +#include + +@implementation Queue + +- (void) enqueueObject: newObject +{ + [self prependObject: newObject]; +} + +- dequeueObject +{ + id ret = [[self lastObject] retain]; + [self removeLastObject]; + return [ret autorelease]; +} + +/* Overriding */ +- (void) addObject: newObject +{ + [self enqueueObject: newObject]; +} + +@end diff --git a/Old/RBTree.h b/Old/RBTree.h new file mode 100644 index 000000000..37b67e32c --- /dev/null +++ b/Old/RBTree.h @@ -0,0 +1,39 @@ +/* Interface for Objective-C Red-Black Tree collection object + Copyright (C) 1993,1994 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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 __RBTree_h_GNUSTEP_BASE_INCLUDE +#define __RBTree_h_GNUSTEP_BASE_INCLUDE + +#include + +@protocol RBTreeComprising +- (BOOL) isRed; +- setRed; +- setBlack; +@end + +@interface RBTree : BinaryTree + +@end + +#endif /* __RBTree_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/RBTree.m b/Old/RBTree.m new file mode 100644 index 000000000..d6bc71c01 --- /dev/null +++ b/Old/RBTree.m @@ -0,0 +1,250 @@ +/* Implementation for Objective-C Red-Black Tree collection object + Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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. +*/ + +#include +#include +#include +#include + +#define NODE_IS_RED(NODE) ([NODE isRed]) +#define NODE_IS_BLACK(NODE) (![NODE isRed]) + +/* sentinal */ +static id nilRBNode; + +@implementation RBTree + ++ (void) initialize +{ + if (self == [RBTree class]) + { + nilRBNode = [[RBTreeNode alloc] init]; + [nilRBNode setBlack]; + } +} + +- nilNode +{ + return nilRBNode; +} + +- (void) sortAddObject: newObject +{ + id y; + + [super sortAddObject: newObject]; + [newObject setRed]; + while (newObject != _contents_root + && [[newObject parentNode] isRed]) + { + if ([newObject parentNode] == + [[[newObject parentNode] parentNode] leftNode]) + { + y = [[[newObject parentNode] parentNode] leftNode]; + if ([y isRed]) + { + [[newObject parentNode] setBlack]; + [y setBlack]; + [[[newObject parentNode] parentNode] setRed]; + newObject = [[newObject parentNode] parentNode]; + } + else + { + if (newObject == [[newObject parentNode] rightNode]) + { + newObject = [newObject parentNode]; + [self leftRotateAroundNode:newObject]; + } + [[newObject parentNode] setBlack]; + [[[newObject parentNode] parentNode] setRed]; + [self rightRotateAroundNode: + [[newObject parentNode] parentNode]]; + } + } + else + { + y = [[[newObject parentNode] parentNode] rightNode]; + if ([y isRed]) + { + [[newObject parentNode] setBlack]; + [y setBlack]; + [[[newObject parentNode] parentNode] setRed]; + newObject = [[newObject parentNode] parentNode]; + } + else + { + if (newObject == [[newObject parentNode] leftNode]) + { + newObject = [newObject parentNode]; + [self rightRotateAroundNode:newObject]; + } + [[newObject parentNode] setBlack]; + [[[newObject parentNode] parentNode] setRed]; + [self leftRotateAroundNode: + [[newObject parentNode] parentNode]]; + } + } + } + [_contents_root setBlack]; +} + +- (void) _RBTreeDeleteFixup: x +{ + id w; + + while (x != _contents_root && NODE_IS_BLACK(x)) + { + if (NODE_IS_LEFTCHILD(x)) + { + w = [[x parentNode] rightNode]; + if (NODE_IS_RED(w)) + { + [w setBlack]; + [[x parentNode] setRed]; + [self leftRotateAroundNode:[x parentNode]]; + w = [[x parentNode] rightNode]; + } + if (NODE_IS_BLACK([w leftNode]) && NODE_IS_BLACK([w rightNode])) + { + [w setRed]; + x = [x parentNode]; + } + else + { + if (NODE_IS_BLACK([w rightNode])) + { + [[w leftNode] setBlack]; + [w setRed]; + [self rightRotateAroundNode:w]; + w = [[x parentNode] rightNode]; + } + if (NODE_IS_BLACK([x parentNode])) + [w setBlack]; + else + [w setRed]; + [[x parentNode] setBlack]; + [[w rightNode] setBlack]; + [self leftRotateAroundNode:[x parentNode]]; + x = _contents_root; + } + } + else + { + w = [[x parentNode] leftNode]; + if (NODE_IS_RED(w)) + { + [w setBlack]; + [[x parentNode] setRed]; + [self rightRotateAroundNode:[x parentNode]]; + w = [[x parentNode] leftNode]; + } + if (NODE_IS_BLACK([w rightNode]) && NODE_IS_BLACK([w leftNode])) + { + [w setRed]; + x = [x parentNode]; + } + else + { + if (NODE_IS_BLACK([w leftNode])) + { + [[w rightNode] setBlack]; + [w setRed]; + [self leftRotateAroundNode:w]; + w = [[x parentNode] leftNode]; + } + if (NODE_IS_BLACK([x parentNode])) + [w setBlack]; + else + [w setRed]; + [[x parentNode] setBlack]; + [[w leftNode] setBlack]; + [self rightRotateAroundNode:[x parentNode]]; + x = _contents_root; + } + } + } + [x setBlack]; +} + +- (void) removeObject: oldObject +{ + id x, y; + + if ([oldObject leftNode] == [self nilNode] + || [oldObject rightNode] == [self nilNode]) + y = oldObject; + else + y = [self successorOfObject: oldObject]; + + if ([y leftNode] != [self nilNode]) + x = [y leftNode]; + else + x = [y rightNode]; + + [x setParentNode:[y parentNode]]; + + if ([y parentNode] == [self nilNode]) + _contents_root = x; + else + { + if (y == [[y parentNode] leftNode]) + [[y parentNode] setLeftNode:x]; + else + [[y parentNode] setRightNode:x]; + } + + if (y != oldObject) + { + /* put y in the place of oldObject */ + [y setParentNode:[oldObject parentNode]]; + [y setLeftNode:[oldObject leftNode]]; + [y setRightNode:[oldObject rightNode]]; + if (oldObject == [[oldObject parentNode] leftNode]) + [[oldObject parentNode] setLeftNode:y]; + else + [[oldObject parentNode] setRightNode:oldObject]; + [[oldObject leftNode] setParentNode:y]; + [[oldObject rightNode] setParentNode:y]; + } + + if (NODE_IS_BLACK(y)) + [self _RBTreeDeleteFixup:x]; + + _count--; + + /* Release ownership of the object. */ +#if 0 + [oldObject setRightNode: [self nilNode]]; + [oldObject setLeftNode: [self nilNode]]; + [oldObject setParentNode: [self nilNode]]; +#else + [oldObject setLeftNode: NO_OBJECT]; + [oldObject setRightNode: NO_OBJECT]; + [oldObject setParentNode: NO_OBJECT]; +#endif + [oldObject setBinaryTree: NO_OBJECT]; + [oldObject release]; +} + +@end + diff --git a/Old/RBTreeNode.h b/Old/RBTreeNode.h new file mode 100644 index 000000000..5072e010b --- /dev/null +++ b/Old/RBTreeNode.h @@ -0,0 +1,36 @@ +/* Interface for Objective-C RBTreeNode object + Copyright (C) 1993,1994 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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 __RBTreeNode_h_GNUSTEP_BASE_INCLUDE +#define __RBTreeNode_h_GNUSTEP_BASE_INCLUDE + +#include +#include + +@interface RBTreeNode : BinaryTreeNode +{ + BOOL _red; +} +@end + +#endif /* __RBTreeNode_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/RBTreeNode.m b/Old/RBTreeNode.m new file mode 100644 index 000000000..0987c3e2d --- /dev/null +++ b/Old/RBTreeNode.m @@ -0,0 +1,87 @@ +/* Implementation for Objective-C RBTreeNode objects + Copyright (C) 1993,1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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. +*/ + +#include +#include +#include + +@implementation RBTreeNode + ++ (void) initialize +{ + if (self == [RBTreeNode class]) + [self setVersion:0]; /* beta release */ +} + +- init +{ + [super init]; + _red = YES; + return self; +} + +- (void) encodeWithCoder: aCoder +{ + [super encodeWithCoder:aCoder]; + [aCoder encodeValueOfObjCType:@encode(BOOL) at:&_red withName:@"RBTreeNode isRed"]; +} + +- initWithCoder: aCoder +{ + [self initWithCoder:aCoder]; + [aCoder decodeValueOfObjCType:@encode(BOOL) at:&_red withName:NULL]; + return self; +} + +- write: (TypedStream*)aStream +{ + [super write:aStream]; + objc_write_type(aStream, @encode(BOOL), &_red); + return self; +} + +- read: (TypedStream*)aStream +{ + [super read:aStream]; + objc_read_type(aStream, @encode(BOOL), &_red); + return self; +} + +- (BOOL) isRed +{ + return _red; +} + +- setRed +{ + _red = YES; + return self; +} + +- setBlack +{ + _red = NO; + return self; +} + +@end diff --git a/Old/README b/Old/README new file mode 100644 index 000000000..efed3c520 --- /dev/null +++ b/Old/README @@ -0,0 +1,13 @@ + +* WARNING * +This directory contains code that does not (and is not intended to) build. +* WARNING * + +The source code here is obsolete - mostly from the original libObjects library +that was used as a bais for gstep-base. + +The files have been preserved in case we want to re-use them at some point, +or use them as the basis/inspiration for an additional library. + +They are NOT part of gstep-base proper. + diff --git a/Old/RNGAdditiveCongruential.h b/Old/RNGAdditiveCongruential.h new file mode 100644 index 000000000..1e6a79c9f --- /dev/null +++ b/Old/RNGAdditiveCongruential.h @@ -0,0 +1,43 @@ +/* Interface for additive congruential pseudo-random num generating + Copyright (C) 1994 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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. +*/ + +/* Additive Congruential Method, + from Robert Sedgewick, "Algorithms" */ + +#ifndef __RNGAdditiveCongruential_h_GNUSTEP_BASE_INCLUDE +#define __RNGAdditiveCongruential_h_GNUSTEP_BASE_INCLUDE + +#include + +@interface RNGAdditiveCongruential : NSObject +{ + long *table; + int table_size; + int tap1; + int tap2; + int index; +} + +@end + +#endif /* __RNGAdditiveCongruential_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/RNGAdditiveCongruential.m b/Old/RNGAdditiveCongruential.m new file mode 100644 index 000000000..a2c784cb2 --- /dev/null +++ b/Old/RNGAdditiveCongruential.m @@ -0,0 +1,112 @@ +/* Implementation additive congruential pseudo-random num generating + Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: July 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. +*/ + +#include +#include +#include +#include + +/* Additive Congruential Method, + from Robert Sedgewick, "Algorithms" */ + +/* The Chi^2 test results for this RNG is bad. + xxx Find the bug. */ + +@implementation RNGAdditiveCongruential + +- initWithTableSize: (int)s tapsAtOffsets: (int)t1 :(int)t2 +{ + [super init]; + table_size = s; + tap1 = t1; + tap2 = t2; + OBJC_MALLOC(table, long, table_size); + [self setRandomSeed:0]; + return self; +} + +- (void) encodeWithCoder: anEncoder +{ + [self notImplemented:_cmd]; +} + +- initWithCoder: aDecoder +{ + [self notImplemented:_cmd]; + return self; +} + +- (void) dealloc +{ + OBJC_FREE(table); + [super dealloc]; +} + +- init +{ + [self initWithTableSize:55 tapsAtOffsets:31 :55]; + return self; +} + +#define BITS_PER_CHAR 8 +#define HIGH_BYTE(X) ((X) / (1 << (sizeof(X)-1) * BITS_PER_CHAR)) + +- (long) nextRandom +{ + int i; + long result = 0; + + /* Grab only the high bytes---they are the most random */ + for (i = 0; i < sizeof(long); i++) + { + index = (index + 1) % table_size; + table[index] = (table[(index + table_size - tap1) % table_size] + + + table[(index + table_size - tap2) % table_size]); + result = (result << BITS_PER_CHAR) + HIGH_BYTE(table[index]); + } + return result; +} + +- (void) setRandomSeed: (long)s +{ + /* Fill the table with the linear congruential method, + from Robert Sedgewick, "Algorithms" */ + /* b must be x21, with x even, one less number of digits than ULONG_MAX */ + unsigned long b = ((ULONG_MAX / 1000) * 200) + 21; + unsigned char *byte_table = (unsigned char*) table; + int byte_table_size = table_size * sizeof(*table); + int i; + + for (i = 0; i < byte_table_size; i++) + { + s = s * b + 1; + byte_table[i] = HIGH_BYTE(s); + } + + /* Reset index to beginning */ + index = 0; + return; +} + +@end diff --git a/Old/RNGBerkeley.h b/Old/RNGBerkeley.h new file mode 100644 index 000000000..2d6a8e15e --- /dev/null +++ b/Old/RNGBerkeley.h @@ -0,0 +1,73 @@ +/* Interface for Berkeley random()-compatible generation for Objective-C + + Reworked by: Andrew Kachites McCallum + Date: May 1993 + + 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 __RNGBerkeley_h_GNUSTEP_BASE_INCLUDE +#define __RNGBerkeley_h_GNUSTEP_BASE_INCLUDE + +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * This is derived from the Berkeley source: + * @(#)random.c 5.5 (Berkeley) 7/6/88 + * It was reworked for the GNU C Library by Roland McGrath. + * It was reworked for the GNU Objective-C Library by Andrew Kachites McCallum + */ + +#include + +@interface RNGBerkeley : NSObject +{ + int foo[2]; + long int randtbl[32]; /* Size must match DEG_3 + 1 from RNGBerkeley.m */ + long int *fptr; + long int *rptr; + long int *state; + int rand_type; + int rand_deg; + int rand_sep; + long int *end_ptr; +} + +- (void) _srandom: (unsigned int)x; +- (void*) _initstateSeed: (unsigned int)seed + state: (void*)arg_state + size: (size_t)n; +- (void*) _setstate: (void*)arg_state; + +@end + +#endif /* __RNGBerkeley_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/RNGBerkeley.m b/Old/RNGBerkeley.m new file mode 100644 index 000000000..dbc6dcbad --- /dev/null +++ b/Old/RNGBerkeley.m @@ -0,0 +1,443 @@ +/* Implementation of Berkeley random()-compatible generation for Objective-C + + Reworked by: Andrew Kachites McCallum + Date: July 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. +*/ + +/* + * Copyright (c) 1983, 1995 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * This is derived from the Berkeley source: + * @(#)random.c 5.5 (Berkeley) 7/6/88 + * It was reworked for the GNU C Library by Roland McGrath. + * It was reworked for the GNU Objective-C Library by Andrew Kachites McCallum + */ + +#include +#include +#include +#include +#include +#include +#include + +//#include + +/* Deal with bcopy: */ +#if STDC_HEADERS || HAVE_STRING_H +#include +/* An ANSI string.h and pre-ANSI memory.h might conflict. */ +#if !STDC_HEADERS && HAVE_MEMORY_H +#include +#endif /* not STDC_HEADERS and HAVE_MEMORY_H */ +#define index strchr +#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 +/* memory.h and strings.h conflict on some systems. */ +#endif /* not STDC_HEADERS and not HAVE_STRING_H */ + + +/* An improved random number generation package. In addition to the standard + rand()/srand() like interface, this package also has a special state info + interface. The initstate() routine is called with a seed, an array of + bytes, and a count of how many bytes are being passed in; this array is + then initialized to contain information for random number generation with + that much state information. Good sizes for the amount of state + information are 32, 64, 128, and 256 bytes. The state can be switched by + calling the setstate() function with the same array as was initiallized + with initstate(). By default, the package runs with 128 bytes of state + information and generates far better random numbers than a linear + congruential generator. If the amount of state information is less than + 32 bytes, a simple linear congruential R.N.G. is used. Internally, the + state information is treated as an array of longs; the zeroeth element of + the array is the type of R.N.G. being used (small integer); the remainder + of the array is the state information for the R.N.G. Thus, 32 bytes of + state information will give 7 longs worth of state information, which will + allow a degree seven polynomial. (Note: The zeroeth word of state + information also has some other information stored in it; see setstate + for details). The random number generation technique is a linear feedback + shift register approach, employing trinomials (since there are fewer terms + to sum up that way). In this approach, the least significant bit of all + the numbers in the state table will act as a linear feedback shift register, + and will have period 2^deg - 1 (where deg is the degree of the polynomial + being used, assuming that the polynomial is irreducible and primitive). + The higher order bits will have longer periods, since their values are + also influenced by pseudo-random carries out of the lower bits. The + total period of the generator is approximately deg*(2**deg - 1); thus + doubling the amount of state information has a vast influence on the + period of the generator. Note: The deg*(2**deg - 1) is an approximation + only good for large deg, when the period of the shift register is the + dominant factor. With deg equal to seven, the period is actually much + longer than the 7*(2**7 - 1) predicted by this formula. */ + + + +/* For each of the currently supported random number generators, we have a + break value on the amount of state information (you need at least thi + bytes of state info to support this random number generator), a degree for + the polynomial (actually a trinomial) that the R.N.G. is based on, and + separation between the two lower order coefficients of the trinomial. */ + + +/* Linear congruential. */ +#define TYPE_0 0 +#define BREAK_0 8 +#define DEG_0 0 +#define SEP_0 0 + +/* x**7 + x**3 + 1. */ +#define TYPE_1 1 +#define BREAK_1 32 +#define DEG_1 7 +#define SEP_1 3 + +/* x**15 + x + 1. */ +#define TYPE_2 2 +#define BREAK_2 64 +#define DEG_2 15 +#define SEP_2 1 + +/* x**31 + x**3 + 1. */ +#define TYPE_3 3 +#define BREAK_3 128 +#define DEG_3 31 +#define SEP_3 3 + +/* x**63 + x + 1. */ +#define TYPE_4 4 +#define BREAK_4 256 +#define DEG_4 63 +#define SEP_4 1 + +/* Array versions of the above information to make code run faster. + Relies on fact that TYPE_i == i. */ + +#define MAX_TYPES 5 /* Max number of types above. */ + +static int degrees[MAX_TYPES] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 }; +static int seps[MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 }; + + + +/* Initially, everything is set up as if from: + initstate(1, randtbl, 128); + Note that this initialization takes advantage of the fact that srandom + advances the front and rear pointers 10*rand_deg times, and hence the + rear pointer which starts at 0 will also end up at zero; thus the zeroeth + element of the state information, which contains info about the current + position of the rear pointer is just + (MAX_TYPES * (rptr - state)) + TYPE_3 == TYPE_3. */ + +#if 0 /* moved to RNGBerkeley.h -am */ +static long int randtbl[DEG_3 + 1] = + { + TYPE_3, + -851904987, -43806228, -2029755270, 1390239686, -1912102820, + -485608943, 1969813258, -1590463333, -1944053249, 455935928, 508023712, + -1714531963, 1800685987, -2015299881, 654595283, -1149023258, + -1470005550, -1143256056, -1325577603, -1568001885, 1275120390, + -607508183, -205999574, -1696891592, 1492211999, -1528267240, + -952028296, -189082757, 362343714, 1424981831, 2039449641, + }; +#endif /* moved to RNGBerkeley.h -am */ + +/* FPTR and RPTR are two pointers into the state info, a front and a rear + pointer. These two pointers are always rand_sep places aparts, as they + cycle through the state information. (Yes, this does mean we could get + away with just one pointer, but the code for random is more efficient + this way). The pointers are left positioned as they would be from the call: + initstate(1, randtbl, 128); + (The position of the rear pointer, rptr, is really 0 (as explained above + in the initialization of randtbl) because the state table pointer is set + to point to randtbl[1] (as explained below).) */ + +#if 0 /* moved to RNGBerkeley.h -am */ +static long int *fptr = &randtbl[SEP_3 + 1]; +static long int *rptr = &randtbl[1]; +#endif /* moved to RNGBerkeley.h -am */ + + +/* The following things are the pointer to the state information table, + the type of the current generator, the degree of the current polynomial + being used, and the separation between the two pointers. + Note that for efficiency of random, we remember the first location of + the state information, not the zeroeth. Hence it is valid to access + state[-1], which is used to store the type of the R.N.G. + Also, we remember the last location, since this is more efficient than + indexing every time to find the address of the last element to see if + the front and rear pointers have wrapped. */ + +#if 0 /* moved to RNGBerkeley.h -am */ +static long int *state = &randtbl[1]; + +static int rand_type = TYPE_3; +static int rand_deg = DEG_3; +static int rand_sep = SEP_3; + +static long int *end_ptr = &randtbl[sizeof(randtbl) / sizeof(randtbl[0])]; +#endif /* moved to RNGBerkeley.h -am */ + + +@implementation RNGBerkeley + +- init +{ + static long int static_randtbl[DEG_3 + 1] = + { + TYPE_3, + -851904987, -43806228, -2029755270, 1390239686, -1912102820, + -485608943, 1969813258, -1590463333, -1944053249, 455935928, 508023712, + -1714531963, 1800685987, -2015299881, 654595283, -1149023258, + -1470005550, -1143256056, -1325577603, -1568001885, 1275120390, + -607508183, -205999574, -1696891592, 1492211999, -1528267240, + -952028296, -189082757, 362343714, 1424981831, 2039449641, + }; + [super init]; + bcopy(static_randtbl, randtbl, sizeof(randtbl)); + fptr = &randtbl[SEP_3 + 1]; + rptr = &randtbl[1]; + state = &randtbl[1]; + rand_type = TYPE_3; + rand_deg = DEG_3; + rand_sep = SEP_3; + end_ptr = &randtbl[sizeof(randtbl) / sizeof(randtbl[0])]; + return self; +} + +/* Initialize the random number generator based on the given seed. If the + type is the trivial no-state-information type, just remember the seed. + Otherwise, initializes state[] based on the given "seed" via a linear + congruential generator. Then, the pointers are set to known locations + that are exactly rand_sep places apart. Lastly, it cycles the state + information a given number of times to get rid of any initial dependencies + introduced by the L.C.R.N.G. Note that the initialization of randtbl[] + for default usage relies on values produced by this routine. */ +- (void) _srandom: (unsigned int)x +{ + state[0] = x; + if (rand_type != TYPE_0) + { + register long int i; + for (i = 1; i < rand_deg; ++i) + state[i] = (1103515145 * state[i - 1]) + 12345; + fptr = &state[rand_sep]; + rptr = &state[0]; + for (i = 0; i < 10 * rand_deg; ++i) + [self nextRandom]; /* (void) __random(); */ + } +} + +- (void) setRandomSeed: (long)aSeed +{ + [self _srandom:aSeed]; + return; +} + + +/* Initialize the state information in the given array of N bytes for + future random number generation. Based on the number of bytes we + are given, and the break values for the different R.N.G.'s, we choose + the best (largest) one we can and set things up for it. srandom is + then called to initialize the state information. Note that on return + from srandom, we set state[-1] to be the type multiplexed with the current + value of the rear pointer; this is so successive calls to initstate won't + lose this information and will be able to restart with setstate. + Note: The first thing we do is save the current state, if any, just like + setstate so that it doesn't matter when initstate is called. + Returns a pointer to the old state. */ +- (void*) _initstateSeed: (unsigned int)seed + state: (void*)arg_state + size: (size_t)n +{ + void* ostate = (void*) &state[-1]; + + if (rand_type == TYPE_0) + state[-1] = rand_type; + else + state[-1] = (MAX_TYPES * (rptr - state)) + rand_type; + if (n < BREAK_1) + { + if (n < BREAK_0) + { + errno = EINVAL; + return NULL; + } + rand_type = TYPE_0; + rand_deg = DEG_0; + rand_sep = SEP_0; + } + else if (n < BREAK_2) + { + rand_type = TYPE_1; + rand_deg = DEG_1; + rand_sep = SEP_1; + } + else if (n < BREAK_3) + { + rand_type = TYPE_2; + rand_deg = DEG_2; + rand_sep = SEP_2; + } + else if (n < BREAK_4) + { + rand_type = TYPE_3; + rand_deg = DEG_3; + rand_sep = SEP_3; + } + else + { + rand_type = TYPE_4; + rand_deg = DEG_4; + rand_sep = SEP_4; + } + + state = &((long int *) arg_state)[1]; /* First location. */ + /* Must set END_PTR before srandom. */ + end_ptr = &state[rand_deg]; + [self _srandom:seed]; /*__srandom(seed); */ + if (rand_type == TYPE_0) + state[-1] = rand_type; + else + state[-1] = (MAX_TYPES * (rptr - state)) + rand_type; + + return ostate; +} + + +/* Restore the state from the given state array. + Note: It is important that we also remember the locations of the pointers + in the current state information, and restore the locations of the pointers + from the old state information. This is done by multiplexing the pointer + location into the zeroeth word of the state information. Note that due + to the order in which things are done, it is OK to call setstate with the + same state as the current state + Returns a pointer to the old state information. */ +- (void*) _setstate: (void*)arg_state +{ + register long int *new_state = (long int *) arg_state; + register int type = new_state[0] % MAX_TYPES; + register int rear = new_state[0] / MAX_TYPES; + void* ostate = (void*) &state[-1]; + + if (rand_type == TYPE_0) + state[-1] = rand_type; + else + state[-1] = (MAX_TYPES * (rptr - state)) + rand_type; + + switch (type) + { + case TYPE_0: + case TYPE_1: + case TYPE_2: + case TYPE_3: + case TYPE_4: + rand_type = type; + rand_deg = degrees[type]; + rand_sep = seps[type]; + break; + default: + /* State info munged. */ + errno = EINVAL; + return NULL; + } + + state = &new_state[1]; + if (rand_type != TYPE_0) + { + rptr = &state[rear]; + fptr = &state[(rear + rand_sep) % rand_deg]; + } + /* Set end_ptr too. */ + end_ptr = &state[rand_deg]; + + return ostate; +} + + +/* If we are using the trivial TYPE_0 R.N.G., just do the old linear + congruential bit. Otherwise, we do our fancy trinomial stuff, which is the + same in all ther other cases due to all the global variables that have been + set up. The basic operation is to add the number at the rear pointer into + the one at the front pointer. Then both pointers are advanced to the next + location cyclically in the table. The value returned is the sum generated, + reduced to 31 bits by throwing away the "least random" low bit. + Note: The code takes advantage of the fact that both the front and + rear pointers can't wrap on the same call by not testing the rear + pointer if the front one has wrapped. Returns a 31-bit random number. */ + +- (long) nextRandom +{ + if (rand_type == TYPE_0) + { + state[0] = ((state[0] * 1103515245) + 12345) & LONG_MAX; + return state[0]; + } + else + { + long int i; + *fptr += *rptr; + /* Chucking least random bit. */ + i = (*fptr >> 1) & LONG_MAX; + ++fptr; + if (fptr >= end_ptr) + { + fptr = state; + ++rptr; + } + else + { + ++rptr; + if (rptr >= end_ptr) + rptr = state; + } + return i; + } +} + +- (void) encodeWithCoder: anEncoder +{ + [self notImplemented:_cmd]; +} + +- initWithCoder: aDecoder +{ + [self notImplemented:_cmd]; + return self; +} + +@end diff --git a/Old/Random.h b/Old/Random.h new file mode 100644 index 000000000..1df32c2fc --- /dev/null +++ b/Old/Random.h @@ -0,0 +1,68 @@ +/* Interface for Objective-C object providing randoms in uniform distribution + Copyright (C) 1994 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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 __Random_h_GNUSTEP_BASE_INCLUDE +#define __Random_h_GNUSTEP_BASE_INCLUDE + +#include + +@interface Random : NSObject +{ + id rng; +} + ++ initialize; ++ (id ) defaultRandomGeneratorClass; ++ setDefaultRandomGeneratorClass: (id )aRNG; + ++ (float) chiSquareOfRandomGenerator: (id )aRNG + iterations: (int)n + range: (long)r; ++ (float) chiSquareOfRandomGenerator: (id )aRNG; + +- init; + +- setRandomSeedFromClock; +- setRandomSeed: (long)seed; + +- (long) randomInt; +- (long) randomIntBetween: (long)lowBound and: (long)highBound; +- (long) randomDie: (long)numSides; /* between 0 and numSides-1 */ + +- (BOOL) randomCoin; +- (BOOL) randomCoinWithProbability: (double)p; + +- (float) randomFloat; +- (float) randomFloatBetween: (float)lowBound and: (float)highBound; +- (float) randomFloatProbability; + +- (double) randomDouble; +- (double) randomDoubleBetween: (double)lowBound and: (double)highBound; +- (double) randomDoubleProbability; + +- read: (TypedStream*)aStream; +- write: (TypedStream*)aStream; + +@end + +#endif /* __Random_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/Random.m b/Old/Random.m new file mode 100644 index 000000000..a567f605f --- /dev/null +++ b/Old/Random.m @@ -0,0 +1,306 @@ +/* Implementation Objective-C object providing randoms in uniform distribution + Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: July 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. +*/ + +/* TODO: + RNGBerkeley nextRandom returns only positive numbers + RNGAdditiveCongruential nextRandom returns positive and negative numbers +*/ + +#include +#include +#include +#include +#include +#include +#include + +typedef union { + float f; + unsigned long u; +} float_and_long_u; + +typedef union { + double d; + unsigned long u[2]; +} double_and_long_u; + +static float_and_long_u singleMantissa; +static double_and_long_u doubleMantissa; + +static id defaultRNG = nil; +@class RNGBerkeley; + +@implementation Random + ++ initialize +{ + if (self == [Random class]) + { + defaultRNG = [RNGBerkeley class]; + NSAssert(sizeof(double) == 2 * sizeof(long), NSInternalInconsistencyException); + NSAssert(sizeof(float) == sizeof(long), NSInternalInconsistencyException); + + /* Following taken from libg++ */ + + /* + The following is a hack that I attribute to + Andres Nowatzyk at CMU. The intent of the loop + is to form the smallest number 0 <= x < 1.0, + which is then used as a mask for two longwords. + this gives us a fast way way to produce double + precision numbers from longwords. + + I know that this works for IEEE and VAX floating + point representations. + + A further complication is that gnu C will blow + the following loop, unless compiled with -ffloat-store, + because it uses extended representations for some of + of the comparisons. Thus, we have the following hack. + If we could specify #pragma optimize, we wouldn't need this. + */ + { + double_and_long_u t; + float_and_long_u s; + +#if _IEEE == 1 + + t.d = 1.5; + if ( t.u[1] == 0 ) { // sun word order? + t.u[0] = 0x3fffffff; + t.u[1] = 0xffffffff; + } + else { + t.u[0] = 0xffffffff; // encore word order? + t.u[1] = 0x3fffffff; + } + + s.u = 0x3fffffff; +#else + volatile double x = 1.0; /* volatile needed when fp hardware used, + and has greater precision than memory + doubles */ + double y = 0.5; + volatile float xx = 1.0; /* volatile needed when fp hardware used, + and has greater precision than memory + floats */ + float yy = 0.5; + do { /* find largest fp-number < 2.0 */ + t.d = x; + x += y; + y *= 0.5; + } while (x != t.d && x < 2.0); + + do { /*find largest fp-number < 2.0 */ + s.f = xx; + xx += yy; + yy *= 0.5; + } while (xx != s.f && xx < 2.0); +#endif + // set doubleMantissa to 1 for each doubleMantissa bit; + doubleMantissa.d = 1.0; + doubleMantissa.u[0] ^= t.u[0]; + doubleMantissa.u[1] ^= t.u[1]; + + // set singleMantissa to 1 for each singleMantissa bit; + singleMantissa.f = 1.0; + singleMantissa.u ^= s.u; + } + } + return self; +} + ++ setDefaultRandomGeneratorClass: (id )aRNG +{ + defaultRNG = aRNG; + return self; +} + ++ (id ) defaultRandomGeneratorClass +{ + return defaultRNG; +} + +/* For testing randomness of a random generator, + the closer to r the returned value is, the better the randomness. */ + ++ (float) chiSquareOfRandomGenerator: (id )aRNG + iterations: (int)n + range: (long)r +{ + long table[r]; + int i, j; + + for (i = 0; i < r; i++) + table[i] = 0; + for (i = 0; i < n; i++) + { + j = ABS([aRNG nextRandom]) % r; + table[j]++; + } + j = 0; + for (i = 0; i < r; i++) + j += table[i] * table[i]; + return ((((float)r * j) / n) - n); +} + +/* For testing randomness of a random generator, + the closer to 1.0 the returned value is, the better the randomness. */ + ++ (float) chiSquareOfRandomGenerator: (id )aRNG +{ + return [self chiSquareOfRandomGenerator:aRNG + iterations:1000 + range:100] / 100.0; +} + +- initWithRandomGenerator: (id )aRNG +{ + [super init]; + rng = aRNG; + return self; +} + +- init +{ + /* Without the (id) we get: + Random.m: In function `_i_Random__init': + Random.m:172: warning: method `alloc' not implemented by protocol. + This is a bug in gcc. + */ + return [self initWithRandomGenerator: + [[(id)[[self class] defaultRandomGeneratorClass] alloc] init]]; +} + +- setRandomSeedFromClock +{ + [self setRandomSeed:[Time secondClockValue]]; + return self; +} + +- setRandomSeed: (long)seed +{ + [rng setRandomSeed:seed]; + return self; +} + +- (long) randomInt +{ + return [rng nextRandom]; +} + +- (long) randomIntBetween: (long)lowBound and: (long)highBound +{ + return ([rng nextRandom] % (highBound - lowBound + 1) + lowBound); +} + +/* return between 0 and numSides-1 */ +- (long) randomDie: (long)numSides +{ + return ([rng nextRandom] % numSides); +} + +- (BOOL) randomCoin +{ + return ([rng nextRandom] % 2); +} + +- (BOOL) randomCoinWithProbability: (double)p +{ + return (p >= [self randomDoubleProbability]); +} + +/* Returns 0.0 <= r < 1.0. Is this what people want? + I'd like it to return 1.0 also. */ +- (float) randomFloat +{ + union {long i; float f;} result; + result.f = 1.0; + result.i |= ([rng nextRandom] & singleMantissa.u); + result.f -= 1.0; + NSAssert(result.f < 1.0 && result.f >= 0, NSInternalInconsistencyException); + return result.f; +} + +- (float) randomFloatBetween: (float)lowBound and: (float)highBound +{ + return ([self randomFloat] * (highBound - lowBound) + lowBound); +} + +- (float) randomFloatProbability +{ + return [self randomFloat]; +} + +/* Returns 0.0 <= r < 1.0. Is this what people want? + I'd like it to return 1.0 also. */ +- (double) randomDouble +{ + union {unsigned long u[2]; double d;} result; + + result.d = 1.0; + result.u[0] |= ([rng nextRandom] & doubleMantissa.u[0]); + result.u[1] |= ([rng nextRandom] & doubleMantissa.u[1]); + result.d -= 1.0; + NSAssert(result.d < 1.0 && result.d >= 0, NSInternalInconsistencyException); + return result.d; +} + +- (double) randomDoubleBetween: (double)lowBound and: (double)highBound +{ + return [self randomDouble] * (highBound - lowBound); +} + +- (double) randomDoubleProbability +{ + return [self randomDouble]; +} + +- (void) encodeWithCoder: anEncoder +{ + [self notImplemented:_cmd]; +} + +- initWithCoder: aDecoder +{ + [self notImplemented:_cmd]; + return self; +} + +- write: (TypedStream*)aStream +{ + [super write:aStream]; + // [rng read:aStream]; + [self notImplemented:_cmd]; + return self; +} + +- read: (TypedStream*)aStream +{ + [super read:aStream]; + // [rng read:aStream]; + [self notImplemented:_cmd]; + return self; +} + +@end diff --git a/Old/RandomGenerating.h b/Old/RandomGenerating.h new file mode 100644 index 000000000..3422de1d0 --- /dev/null +++ b/Old/RandomGenerating.h @@ -0,0 +1,36 @@ +/* Protocol for Objective-C objects that generate random bits + Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: May 1993 + + 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 __RandomGenerating_h_GNUSTEP_BASE_INCLUDE +#define __RandomGenerating_h_GNUSTEP_BASE_INCLUDE + +#include + +@protocol RandomGenerating + +- (void) setRandomSeed: (long)seed; +- (long) nextRandom; + +@end + +#endif /* __RandomGenerating_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/RawCStream.h b/Old/RawCStream.h new file mode 100644 index 000000000..b0ead9d56 --- /dev/null +++ b/Old/RawCStream.h @@ -0,0 +1,36 @@ +/* Interface for GNU Objective-C raw stream object for archiving + Copyright (C) 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Written: Jan 1996 + + 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 __RawCStream_h_GNUSTEP_BASE_INCLUDE +#define __RawCStream_h_GNUSTEP_BASE_INCLUDE + +#include +#include + +@interface RawCStream : CStream + ++ setDebugging: (BOOL)f; + +@end + +#endif /* __RawCStream_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/RawCStream.m b/Old/RawCStream.m new file mode 100644 index 000000000..ed30388d3 --- /dev/null +++ b/Old/RawCStream.m @@ -0,0 +1,296 @@ +/* Implementation of GNU Objective-C raw-binary stream for archiving + Copyright (C) 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Written: Jan 1996 + + 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. + */ + +/* Use this CStream subclass when you are encoding/decoding on the + same architecture, and you care about time and space. + WARNING: This encoding is *not* machine-independent. */ + +#include +#include +#include +#include +#include +#include +#include + +#define DEFAULT_FORMAT_VERSION 0 + +#define ROUND(V, A) \ + ({ typeof(V) __v=(V); typeof(A) __a=(A); \ + __a*((__v+__a-1)/__a); }) + +@implementation RawCStream + + +/* For debugging */ + +static BOOL debug_binary_coder; + ++ setDebugging: (BOOL)f +{ + debug_binary_coder = f; + return self; +} + ++ debugStderrCoder +{ + static id c = nil; + + if (!c) + c = [[TextCStream alloc] + initForWritingToStream: [StdioStream standardError]]; + return c; +} + +- (void) encodeName: (NSString*) name +{ + if (debug_binary_coder) + [[[self class] debugStderrCoder] + encodeName:name]; +} + + + +/* Encoding/decoding C values */ + +- (void) encodeValueOfCType: (const char*)type + at: (const void*)d + withName: (NSString*) name +{ + if (debug_binary_coder) + { + [[[self class] debugStderrCoder] + encodeValueOfCType:type + at:d + withName:name]; + } + + if (!type) + [NSException raise:NSInvalidArgumentException format:@"type is NULL"]; + + NSAssert(*type != '@', @"tried to encode an \"ObjC\" type"); + NSAssert(*type != '^', @"tried to encode an \"ObjC\" type"); + NSAssert(*type != ':', @"tried to encode an \"ObjC\" type"); + + switch (*type) + { + case _C_CHARPTR: + { + int length = strlen(*(char**)d); + [self encodeValueOfCType:@encode(int) + at:&length withName:@"BinaryCStream char* length"]; + [stream writeBytes:*(char**)d length:length]; + break; + } + + case _C_CHR: + case _C_UCHR: + [stream writeByte:*(unsigned char*)d]; + break; + + case _C_SHT: + case _C_USHT: + [stream writeBytes:d length:sizeof(short)]; + break; + + case _C_INT: + case _C_UINT: + [stream writeBytes:d length:sizeof(int)]; + break; + + case _C_LNG: + case _C_ULNG: + [stream writeBytes:d length:sizeof(long)]; + break; + + case _C_FLT: + [stream writeBytes:d length:sizeof(float)]; + break; + + case _C_DBL: + [stream writeBytes:d length:sizeof(double)]; + break; + + case _C_ARY_B: + { + int len = atoi (type+1); /* xxx why +1 ? */ + int offset; + + while (isdigit(*++type)); + offset = objc_sizeof_type(type); + while (len-- > 0) + { + /* Change this so we don't re-write type info every time. */ + [self encodeValueOfCType: type + at: d + withName: NULL]; + ((char*)d) += offset; + } + break; + } + case _C_STRUCT_B: + { + int acc_size = 0; + int align; + + while (*type != _C_STRUCT_E && *type++ != '='); /* skip "=" */ + while (*type != _C_STRUCT_E) + { + align = objc_alignof_type (type); /* pad to alignment */ + acc_size = ROUND (acc_size, align); + [self encodeValueOfCType: type + at: ((char*)d)+acc_size + withName: NULL]; + acc_size += objc_sizeof_type (type); /* add component size */ + type = objc_skip_typespec (type); /* skip component */ + } + break; + } + default: + [self error:"Unrecognized Type %s", type]; + } +} + +- (void) decodeValueOfCType: (const char*)type + at: (void*)d + withName: (NSString* *)namePtr +{ + if (!type) + [NSException raise:NSInvalidArgumentException format:@"type is NULL"]; + + NSAssert(*type != '@', @"tried to decode an \"ObjC\" type"); + NSAssert(*type != '^', @"tried to decode an \"ObjC\" type"); + NSAssert(*type != ':', @"tried to decode an \"ObjC\" type"); + + switch (*type) + { + case _C_CHARPTR: + { + int length; + [self decodeValueOfCType:@encode(int) + at:&length withName:NULL]; + OBJC_MALLOC(*(char**)d, char, length+1); + [stream readBytes:*(char**)d length:length]; + (*(char**)d)[length] = '\0'; + break; + } + + case _C_CHR: + case _C_UCHR: + [stream readByte:d]; + break; + + case _C_SHT: + case _C_USHT: + [stream readBytes:d length:sizeof(short)]; + break; + + case _C_INT: + case _C_UINT: + [stream readBytes:d length:sizeof(int)]; + break; + + case _C_LNG: + case _C_ULNG: + [stream readBytes:d length:sizeof(long)]; + break; + + case _C_FLT: + [stream readBytes:d length:sizeof(float)]; + break; + + case _C_DBL: + [stream readBytes:d length:sizeof(double)]; + break; + + case _C_ARY_B: + { + /* xxx Do we need to allocate space, just like _C_CHARPTR ? */ + int len = atoi(type+1); + int offset; + while (isdigit(*++type)); + offset = objc_sizeof_type(type); + while (len-- > 0) + { + [self decodeValueOfCType:type + at:d + withName:namePtr]; + ((char*)d) += offset; + } + break; + } + case _C_STRUCT_B: + { + /* xxx Do we need to allocate space just like char* ? No. */ + int acc_size = 0; + int align; + const char *save_type = type; + + while (*type != _C_STRUCT_E && *type++ != '='); /* skip "=" */ + while (*type != _C_STRUCT_E) + { + align = objc_alignof_type (type); /* pad to alignment */ + acc_size = ROUND (acc_size, align); + [self decodeValueOfCType:type + at:((char*)d)+acc_size + withName:namePtr]; + acc_size += objc_sizeof_type (type); /* add component size */ + type = objc_skip_typespec (type); /* skip component */ + } + type = save_type; + break; + } + default: + [self error:"Unrecognized Type %s", type]; + } + + if (debug_binary_coder) + { + [[[self class] debugStderrCoder] + encodeValueOfCType:type + at:d + withName:@"decoding unnamed"]; + } +} + + +/* Returning default format version. */ + ++ (int) defaultFormatVersion +{ + return DEFAULT_FORMAT_VERSION; +} + +- (void) decodeName: (NSString* *)n +{ +#if 1 + if (n) + *n = nil; +#else + if (n) + *n = [[[NSString alloc] init] autorelease]; +#endif +} + +@end + diff --git a/Old/Retaining.h b/Old/Retaining.h new file mode 100644 index 000000000..851b6b1e9 --- /dev/null +++ b/Old/Retaining.h @@ -0,0 +1,100 @@ +/* Protocol for GNU Objective-C objects that can keep a retain count. + Copyright (C) 1993,1994 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: July 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 __Retaining_h_GNUSTEP_BASE_INCLUDE +#define __Retaining_h_GNUSTEP_BASE_INCLUDE + +#include + +@protocol Retaining + +- retain; + +/* Use this message when the sender did not allocate the receiving + object, but the sender wants to keep a reference to the receiving + object. It increments a reference count for the object. The + object will not be deallocated until after a matching release + message is sent to this object. + + IMPORTANT PROGRAMMING CONVENTION: There is no need to send this + message to objects that the sender allocated---allocating an object + already implies that the object will not be deallocated until the + sender releases it. Just as "retain" and "release" messages cancel + each other, one "release" message is needed to cancel the original + allocation. */ + + +- (oneway void) release; + +/* Use this message when the sender is done with the receiving object. + If the sender had the last reference to the object, the object will + be deallocated by sending "dealloc" to it. + + IMPORTANT PROGRAMMING CONVENTION: The sender should only send this + to objects that it has allocated or has retain'ed. */ + + +- (void) dealloc; + +/* This method deallocates the memory for this object. You should not + send this message yourself; it is sent for you by the release + method, which properly manages retain counts. Do, however, + override this method to deallocate any memory allocated by this + object during initialization; the overriding method should call + [super dealloc] at the end. */ + + +- (unsigned) retainCount; + +/* This method returns the retain count to this object. It does + not, however, include the decrements due to stackRelease's. Note + that the returned number is not quite a "reference count" in the + traditional sense; it is less by one in that it is actually a count + of the number of unreleased retain messages sent. A retainCount of + zero implies that there is still one more release necessary to + deallocate the receiver. For example, after an object is created, + its retainCount is zero, but another "release" message is still + required before the object will be deallocated. */ + + +- autorelease; + +/* Use this message when the sender is done with this object, but the + sender doesn't want the object to be deallocated immediately + because the function that sends this message will use this object + as its return value. The object will be queued to receive the + actual "release" message later. + + Due to this delayed release, the function that receives the object + as a return value will have the opportunity to retain the object + before the "release" instigated by the "autorelease" actually + takes place. + + For the object to be autoreleased, you must have previously created + a AutoreleasePool or an AutoreleaseStack. If you don't, however, + your program won't crash, the release corresponding to the + autorelease will just never happen. */ + +@end + +#endif /* __Retaining_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/RunLoop.h b/Old/RunLoop.h new file mode 100644 index 000000000..1861de763 --- /dev/null +++ b/Old/RunLoop.h @@ -0,0 +1,9 @@ +#ifndef __RunLoop_h_GNUSTEP_BASE_INCLUDE +#define __RunLoop_h_GNUSTEP_BASE_INCLUDE + +#include + +#define RunLoop NSRunLoop +#define RunLoopDefaultMode NSDefaultRunLoopMode + +#endif /* __RunLoop_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/Set.h b/Old/Set.h new file mode 100644 index 000000000..82d930542 --- /dev/null +++ b/Old/Set.h @@ -0,0 +1,52 @@ +/* Interface for Objective-C Set collection object + Copyright (C) 1993,1994, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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 __Set_h_GNUSTEP_BASE_INCLUDE +#define __Set_h_GNUSTEP_BASE_INCLUDE + +#include +#include + +@interface Set : Collection +{ + NSHashTable *_contents_hash; // a hashtable to hold the contents; +} + +// MANAGING CAPACITY; ++ (unsigned) defaultCapacity; + +// INITIALIZING AND FREEING; +- initWithCapacity: (unsigned)aCapacity; + +// SET OPERATIONS; +- (void) intersectWithCollection: (id )aCollection; +- (void) unionWithCollection: (id )aCollection; +- (void) differenceWithCollection: (id )aCollection; + +- shallowCopyIntersectWithCollection: (id )aCollection; +- shallowCopyUnionWithCollection: (id )aCollection; +- shallowCopyDifferenceWithCollection: (id )aCollection; + +@end + +#endif /* __Set_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/Set.m b/Old/Set.m new file mode 100644 index 000000000..66257ea72 --- /dev/null +++ b/Old/Set.m @@ -0,0 +1,229 @@ +/* Implementation for Objective-C Set collection object + Copyright (C) 1993,1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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. +*/ + +#include +#include +#include +#include +#include + +#define DEFAULT_SET_CAPACITY 32 + +@implementation Set + +// MANAGING CAPACITY; + +/* Eventually we will want to have better capacity management, + potentially keep default capacity as a class variable. */ + ++ (unsigned) defaultCapacity +{ + return DEFAULT_SET_CAPACITY; +} + +// INITIALIZING AND FREEING; + +/* This is the designated initializer of this class */ +- initWithCapacity: (unsigned)cap +{ + _contents_hash = NSCreateHashTable(NSObjectHashCallBacks, cap); + return self; +} + +/* Override Collection's designated initializer */ +- initWithObjects: (id*)objs count: (unsigned)count +{ + [self initWithCapacity: count]; + while (count--) + [self addObject: objs[count]]; + return self; +} + +/* Archiving must mimic the above designated initializer */ + +- _initCollectionWithCoder: aCoder +{ + [super _initCollectionWithCoder:aCoder]; + _contents_hash = NSCreateHashTable(NSObjectHashCallBacks, + DEFAULT_SET_CAPACITY); + return self; +} + +/* Empty copy must empty an allocCopy'ed version of self */ +- emptyCopy +{ + Set *copy = [super emptyCopy]; + copy->_contents_hash = + NSCreateHashTable (NSObjectHashCallBacks, 0); + return copy; +} + +- (void) dealloc +{ + if (_contents_hash) + { + NSFreeHashTable (_contents_hash); + _contents_hash = 0; + } + [super dealloc]; +} + +// SET OPERATIONS; + +- (void) intersectWithCollection: (id )aCollection +{ + [self removeContentsNotIn: aCollection]; +} + +- (void) unionWithCollection: (id )aCollection +{ + [self addContentsIfAbsentOf: aCollection]; +} + +- (void) differenceWithCollection: (id )aCollection +{ + [self removeContentsIn: aCollection]; +} + +- shallowCopyIntersectWithCollection: (id )aCollection +{ + [self notImplemented: _cmd]; + return nil; +#if 0 + id newColl = [self emptyCopyAs:[self species]]; + void doIt(elt e) + { + if ([aCollection includesElement:e]) + [newColl addElement:e]; + } + [self withElementsCall:doIt]; + return newColl; +#endif +} + +- shallowCopyUnionWithCollection: (id )aCollection +{ + [self notImplemented: _cmd]; + return nil; +#if 0 + id newColl = [self shallowCopy]; + [newColl addContentsOf:aCollection]; + return newColl; +#endif +} + +- shallowCopyDifferenceWithCollection: (id )aCollection +{ + [self notImplemented: _cmd]; + return nil; +#if 0 + id newColl = [self emptyCopyAs:[self species]]; + void doIt(elt e) + { + if (![aCollection includesElement:e]) + [newColl addElement:e]; + } + [self withElementsCall:doIt]; + return newColl; +#endif +} + + +// ADDING; + +- (void) addObject: newObject +{ + NSHashInsert (_contents_hash, newObject); +} + + +// REMOVING AND REPLACING; + +- (void) removeObject: oldObject +{ + NSHashRemove (_contents_hash, oldObject); +} + +/* This must work without sending any messages to content objects */ +- (void) _collectionEmpty +{ + NSResetHashTable (_contents_hash); +} + +- (void) uniqueContents +{ + return; +} + + +// TESTING; + +- (BOOL) containsObject: anObject +{ + return (NSHashGet (_contents_hash, anObject) ? 1 : 0); +} + +- (unsigned) count +{ + if (!_contents_hash) + return 0; + return NSCountHashTable (_contents_hash); +} + +- (unsigned) occurrencesOfObject: anObject +{ + if ([self containsObject: anObject]) + return 1; + else + return 0; +} + +- member: anObject +{ + return NSHashGet(_contents_hash, anObject); +} + + +// ENUMERATING; + +- nextObjectWithEnumState: (void**)enumState +{ + return NSNextHashEnumeratorItem ((*(NSHashEnumerator**)enumState)); +} + +- (void*) newEnumState +{ + void *es; + + OBJC_MALLOC (es, NSMapEnumerator, 1); + *((NSHashEnumerator*)es) = NSEnumerateHashTable (_contents_hash); + return es; +} + +- (void) freeEnumState: (void**)enumState +{ + OBJC_FREE (*enumState); +} + +@end + diff --git a/Old/SplayTree.h b/Old/SplayTree.h new file mode 100644 index 000000000..ada513a8a --- /dev/null +++ b/Old/SplayTree.h @@ -0,0 +1,47 @@ +/* Interface for Objective-C SplayTree collection object + Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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. +*/ + +/* + Splay Tree. + Sleator and Tarjan. "Self-adjusting binary search trees." + Journal of the ACM, 32(3):652-686, 1985. + + includesObject:, minObject, maxObject, nextObject:, sortAddObject, + and removeObject: operations can all be done in O(lg n) amortized time. +*/ + + +#ifndef __SplayTree_h_GNUSTEP_BASE_INCLUDE +#define __SplayTree_h_GNUSTEP_BASE_INCLUDE + +#include + +@interface SplayTree : BinaryTree +{ +} + +- (void) splayNode: aNode; + +@end + +#endif /* __SplayTree_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/SplayTree.m b/Old/SplayTree.m new file mode 100644 index 000000000..eb0abee45 --- /dev/null +++ b/Old/SplayTree.m @@ -0,0 +1,102 @@ +/* Implementation for Objective-C SplayTree collection object + Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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. +*/ + +#include +#include +#include + +@implementation SplayTree + +/* Make this a function ? */ +- (void) _doSplayOperationOnNode: aNode +{ + id parent = [aNode parentNode]; + id parentRightChild = + ((parent == [self nilNode]) ? [self nilNode] : [parent rightNode]); + + if (aNode == _contents_root || aNode == [self nilNode]) + { + return; + } + else if (aNode == parentRightChild) + { + if (parent == _contents_root) + { + [self leftRotateAroundNode:parent]; + } + else if (NODE_IS_RIGHTCHILD(parent)) + { + [self leftRotateAroundNode:[parent parentNode]]; + [self leftRotateAroundNode:parent]; + } + else + /* NODE_IS_LEFTCHILD(parent) */ + { + [self leftRotateAroundNode:parent]; + [self rightRotateAroundNode:[aNode parentNode]]; + } + } + else + /* aNode == parentLeftChild */ + { + if (parent == _contents_root) + { + [self rightRotateAroundNode:parent]; + } + else if (NODE_IS_LEFTCHILD(parent)) + { + [self rightRotateAroundNode:[parent parentNode]]; + [self rightRotateAroundNode:parent]; + } + else + /* NODE_IS_RIGHTCHILD(parent) */ + { + [self rightRotateAroundNode:parent]; + [self leftRotateAroundNode:[aNode parentNode]]; + } + } +} + +- (void) splayNode: aNode +{ + while (aNode != _contents_root) + [self _doSplayOperationOnNode:aNode]; +} + +/* We could make this a little more efficient by doing the splay as + we search down the tree for the correct insertion point. */ +- (void) sortAddObject: newObject +{ + [super sortAddObject: newObject]; + [self splayNode: newObject]; +} + +- (void) removeObject: anObject +{ + id parent = [anObject parentNode]; + [super removeObject: anObject]; + if (parent && parent != [self nilNode]) + [self splayNode:parent]; +} + +@end diff --git a/Old/Stack.h b/Old/Stack.h new file mode 100644 index 000000000..033458792 --- /dev/null +++ b/Old/Stack.h @@ -0,0 +1,40 @@ +/* Interface for Objective-C Stack object + Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: May 1993 + + 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 __Stack_h_GNUSTEP_BASE_INCLUDE +#define __Stack_h_GNUSTEP_BASE_INCLUDE + +#include + +@interface Stack : Array + +- (void) pushObject: anObject; +- popObject; +- topObject; +- (void) duplicateTop; +- (void) exchangeTop; + +@end + +#endif /* __Stack_h_GNUSTEP_BASE_INCLUDE */ + diff --git a/Old/Stack.m b/Old/Stack.m new file mode 100644 index 000000000..da8223513 --- /dev/null +++ b/Old/Stack.m @@ -0,0 +1,66 @@ +/* Implementation for Objective-C Stack object + Copyright (C) 1993, 1994, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: May 1993 + + 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. + */ + +#include +#include +#include + +@implementation Stack + +- (void) pushObject: newObject +{ + [self appendObject: newObject]; +} + +/* Overriding */ +- (void) addObject: newObject +{ + [self pushObject: newObject]; +} + +- popObject +{ + id ret; + ret = [[self lastObject] retain]; + [self removeLastObject]; + return [ret autorelease]; +} + +- topObject +{ + return [self lastObject]; +} + +/* xxx Yipes. What copying semantics do we want here? */ +- (void) duplicateTop +{ + [self pushObject: [self topObject]]; +} + +- (void) exchangeTop +{ + if (_count > 1) + [self swapAtIndeces:_count-1 :_count-2]; +} + +@end diff --git a/Old/StdioStream.h b/Old/StdioStream.h new file mode 100644 index 000000000..9070e11d3 --- /dev/null +++ b/Old/StdioStream.h @@ -0,0 +1,55 @@ +/* Interface for GNU Objective C stdio stream + Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: July 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 __StdioStream_h__GNUSTEP_BASE_INCLUDE +#define __StdioStream_h__GNUSTEP_BASE_INCLUDE + +#include +#include + +@interface StdioStream : Stream +{ + int mode; + FILE *fp; +} + ++ standardIn; ++ standardOut; ++ standardError; + ++ streamWithFilename: (NSString*)name fmode: (const char *)m; +/* xxx Add the others too. */ + +- initWithFilePointer: (FILE*)afp fmode: (const char *)m; +- initWithFilename: (NSString*)name fmode: (const char *)m; +- initWithFileDescriptor: (int)fd fmode: (const char *)m; + +- initWithPipeTo: (NSString*)systemCommand; +- initWithPipeFrom: (NSString*)systemCommand; + +- (void) rewindStream; + +@end + +#endif /* __StdioStream_h__GNUSTEP_BASE_INCLUDE */ + diff --git a/Old/StdioStream.m b/Old/StdioStream.m new file mode 100644 index 000000000..496153b32 --- /dev/null +++ b/Old/StdioStream.m @@ -0,0 +1,309 @@ +/* Implementation of GNU Objective C stdio stream + Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: July 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 _REENTRANT +#define _REENTRANT +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include /* SEEK_* on SunOS 4 */ + +enum { + STREAM_READONLY = 0, + STREAM_READWRITE, + STREAM_WRITEONLY +}; + +extern int +o_vscanf (void *stream, + int (*inchar_func)(void*), + void (*unchar_func)(void*,int), + const char *format, va_list argptr); + +@implementation StdioStream + ++ standardIn +{ + static id stdinStream = nil; + + if (!stdinStream) + stdinStream = [[self alloc] initWithFilePointer:stdin fmode:"r"]; + return stdinStream; +} + ++ standardOut +{ + static id stdoutStream = nil; + + if (!stdoutStream) + stdoutStream = [[self alloc] initWithFilePointer:stdout fmode:"w"]; + return stdoutStream; +} + ++ standardError +{ + static id stderrStream = nil; + + if (!stderrStream) + stderrStream = [[self alloc] initWithFilePointer:stderr fmode:"w"]; + return stderrStream; +} + ++ streamWithFilename: (NSString*)name fmode: (const char *)m +{ + return [[[self alloc] + initWithFilename: name fmode: m] + autorelease]; +} + +- initWithFilePointer: (FILE*)afp fmode: (const char *)mo +{ +#if 0 + /* xxx Is this portable? I don't think so. + How do I find out if a FILE* is open for reading/writing? + I want to get rid of the "mode" instance variable. */ + if (afp->_flag & _IOREAD) + mode = STREAM_READONLY; + else if (afp->_flag & _IOWRT) + mode = STREAM_WRITEONLY; + else + mode = STREAM_READWRITE; +#else + if (!strcmp(mo, "rw")) + mode = STREAM_READWRITE; + else if (*mo == 'r') + mode = STREAM_READONLY; + else if (*mo == 'w') + mode = STREAM_WRITEONLY; +#endif + [super init]; + fp = afp; + return self; +} + +- initWithFilename: (NSString*)name fmode: (const char *)m +{ + FILE *afp = fopen([name cString], (char*)m); + if (!afp) + { + id message; + + message = [[NSString alloc] initWithFormat: @"Stream: %s", + strerror(errno)]; + NSLog(message); + [message release]; + [super dealloc]; + return nil; + } + return [self initWithFilePointer:afp fmode:m]; +} + +- initWithFileDescriptor: (int)fd fmode: (const char *)m +{ + FILE *afp = fdopen(fd, (char*)m); + if (!afp) + { + id message; + + message = [[NSString alloc] initWithFormat: @"Stream: %s", + strerror(errno)]; + NSLog(message); + [message release]; + [super dealloc]; + return nil; + } + return [self initWithFilePointer:afp fmode:m]; +} + +- initWithPipeTo: (NSString*) systemCommand +{ +#ifdef __WIN32__ + return nil; +#else + return [self initWithFilePointer: + popen([systemCommand cString], "w") + fmode:"w"]; +#endif +} + +- initWithPipeFrom: (NSString*) systemCommand +{ +#ifdef __WIN32__ + return nil; +#else + return [self initWithFilePointer: + popen([systemCommand cString], "r") + fmode:"r"]; +#endif +} + +- init +{ + return [self initWithFilePointer:stdout fmode:"w"]; +} + +- (int) writeBytes: (const void*)b length: (int)len +{ + int ret = fwrite (b, 1, len, fp); + if (ferror(fp)) + { + [NSException raise: StreamException + format: @"%s", strerror(errno)]; + } + else if (ret != len) + { + [NSException raise: StreamException + format: @"Write bytes differ"]; + } + return ret; +} + +- (int) readBytes: (void*)b length: (int)len +{ + int ret = fread (b, 1, len, fp); + if (ferror(fp)) + { + [NSException raise: StreamException + format: @"%s", strerror(errno)]; + } + return ret; +} + +- (int) writeFormat: (NSString*)format + arguments: (va_list)arg +{ + return vfprintf(fp, [format cString], arg); +} + +static int +stdio_inchar_func(void *s) +{ + return getc((FILE*)s); +} +static void +stdio_unchar_func(void *s, int c) +{ + ungetc(c, (FILE*)s); +} + +- (int) readFormat: (NSString*)format, ... +{ + int ret; + va_list ap; +/* Wow. Why does putting in these nested functions crash the + va_arg stuff in vscanf? */ +#if 0 + int inchar_func() + { + return getc(fp); + } + void unchar_func(int c) + { + ungetc(c, fp); + } +#endif + + va_start(ap, format); + ret = o_vscanf(fp, stdio_inchar_func, stdio_unchar_func, + [format cString], ap); + va_end(ap); + return ret; +} + +- (void) flushStream +{ + fflush(fp); +} + +- (void) close +{ + fclose(fp); + fp = 0; +} + +- (BOOL) isClosed +{ + /* xxx How should this be implemented? */ + [self notImplemented:_cmd]; + return NO; +} + +/* xxx Add "- (BOOL) isOpen" method? */ + +- (void) rewindStream +{ + rewind(fp); +} + +- (void) setStreamPosition: (unsigned)i seekMode: (seek_mode_t)m +{ + fseek(fp, i, m + SEEK_SET - STREAM_SEEK_FROM_START); +} + +- (unsigned) streamPosition +{ + return ftell(fp); +} + +- (BOOL) isAtEof +{ + if (feof(fp)) + return YES; + else + return NO; +} + +- (BOOL) isWritable +{ + if (mode) + return YES; + else + return NO; +} + +- (void) dealloc +{ + if (fp != 0) + fclose(fp); + [super dealloc]; +} + +- (void) encodeWithCoder: (Coder*)anEncoder +{ + [self notImplemented:_cmd]; +} + +- initWithCoder: (Coder*)aDecoder +{ + [self notImplemented:_cmd]; + return self; +} + +@end diff --git a/Old/Stream.h b/Old/Stream.h new file mode 100644 index 000000000..579af4a64 --- /dev/null +++ b/Old/Stream.h @@ -0,0 +1,38 @@ +/* Interface for GNU Objective C byte stream + Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: July 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 __Stream_h__GNUSTEP_BASE_INCLUDE +#define __Stream_h__GNUSTEP_BASE_INCLUDE + +#include + +GS_EXPORT NSString* StreamException; + +@interface Stream : NSObject + +- init; + +@end + +#endif /* __Stream_h__GNUSTEP_BASE_INCLUDE */ + diff --git a/Old/Stream.m b/Old/Stream.m new file mode 100644 index 000000000..0839d9c59 --- /dev/null +++ b/Old/Stream.m @@ -0,0 +1,168 @@ +/* Implementation of GNU Objective C byte stream + Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: July 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. + */ + +#include +#include +#include +#include +#include +#include + +@implementation Stream + +/* This is the designated initializer. */ +- init +{ + return [super init]; +} + +- (int) writeByte: (unsigned char)b +{ + return [self writeBytes:&b length:1]; +} + +- (int) readByte: (unsigned char*)b +{ + return [self readBytes:b length:1]; +} + +- (int) writeBytes: (const void*)b length: (int)l +{ + [self subclassResponsibility:_cmd]; + return 0; +} + +- (int) readBytes: (void*)b length: (int)l +{ + [self subclassResponsibility:_cmd]; + return 0; +} + +- (int) writeFormat: (NSString*)format + arguments: (va_list)arg +{ + [self subclassResponsibility:_cmd]; + return 0; +} + +- (int) writeFormat: (NSString*)format, ... +{ + int ret; + va_list ap; + + va_start(ap, format); + ret = [self writeFormat: format arguments: ap]; + va_end(ap); + return ret; +} + +- (int) readFormat: (NSString*)format + arguments: (va_list)arg +{ + [self subclassResponsibility:_cmd]; + return 0; +} + +- (int) readFormat: (NSString*)format, ... +{ + [self subclassResponsibility:_cmd]; + return 0; +} + +- (void) writeLine: (NSString*)l +{ + const char *s = [l cString]; + [self writeBytes:s length:strlen(s)]; + [self writeBytes:"\n" length:1]; +} + +- (NSString*) readLine +{ + char *l; + [self readFormat: @"%a[^\n]\n", &l]; + return [[[NSString alloc] initWithCStringNoCopy: l + length: strlen (l) + freeWhenDone: YES] + autorelease]; +} + +- (void) flushStream +{ + /* Do nothing. */ +} + +- (void) close +{ + /* Do nothing. */ +} + +- (BOOL) isClosed +{ + return NO; +} + +- (void) setStreamPosition: (unsigned)i seekMode: (seek_mode_t)mode +{ + [self subclassResponsibility:_cmd]; +} + +- (void) setStreamPosition: (unsigned)i +{ + [self setStreamPosition: i seekMode: STREAM_SEEK_FROM_START]; +} + +- (void) rewindStream +{ + [self setStreamPosition:0]; +} + +- (unsigned) streamPosition +{ + [self subclassResponsibility:_cmd]; + return 0; +} + +- (BOOL) isAtEof +{ + [self subclassResponsibility:_cmd]; + return YES; +} + +- (BOOL) isWritable +{ + [self subclassResponsibility:_cmd]; + return NO; +} + +- (void) encodeWithCoder: anEncoder +{ + [self subclassResponsibility:_cmd]; +} + +- initWithCoder: aDecoder +{ + [self subclassResponsibility:_cmd]; + return self; +} + +@end diff --git a/Old/Streaming.h b/Old/Streaming.h new file mode 100644 index 000000000..5543261ae --- /dev/null +++ b/Old/Streaming.h @@ -0,0 +1,75 @@ +/* Protocol for GNU Objective C byte streams + Copyright (C) 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: April 1995 + + 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 __Streaming_h__GNUSTEP_BASE_INCLUDE +#define __Streaming_h__GNUSTEP_BASE_INCLUDE + +#include + +@protocol Streaming + +- (int) writeByte: (unsigned char)b; +- (int) readByte: (unsigned char*)b; + +- (int) writeBytes: (const void*)b length: (int)l; +- (int) readBytes: (void*)b length: (int)l; + +- (int) writeFormat: (NSString*)format, ...; +- (int) readFormat: (NSString*)format, ...; +- (int) writeFormat: (NSString*)format arguments: (va_list)arg; +- (int) readFormat: (NSString*)format arguments: (va_list)arg; + +- (void) writeLine: (NSString*)l; +- (NSString*) readLine; + +- (unsigned) streamPosition; +- (BOOL) isAtEof; +- (void) flushStream; + +/* We must separate the idea of "closing" a stream and "deallocating" a + stream because of delays in deallocation due to -autorelease. */ +- (void) close; +- (BOOL) isClosed; + +- (BOOL) isWritable; + +@end + +typedef enum _seek_mode_t +{ + STREAM_SEEK_FROM_START, + STREAM_SEEK_FROM_CURRENT, + STREAM_SEEK_FROM_END +} seek_mode_t; + +@protocol SeekableStreaming + +- (void) rewindStream; +- (void) setStreamPosition: (unsigned)i; +- (void) setStreamPosition: (unsigned)i seekMode: (seek_mode_t)mode; + +@end + + +#endif /* __Streaming_h__GNUSTEP_BASE_INCLUDE */ + diff --git a/Old/TcpPort.h b/Old/TcpPort.h new file mode 100644 index 000000000..79cd3137f --- /dev/null +++ b/Old/TcpPort.h @@ -0,0 +1,90 @@ +/* Interface for stream based on TCP sockets + Copyright (C) 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: February 1996 + + 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 __TcpPort_h__GNUSTEP_BASE_INCLUDE +#define __TcpPort_h__GNUSTEP_BASE_INCLUDE + +#include +#include +#ifdef __MINGW32__ +# include +#else +#include +#include +#include +#endif +#include + +/* A concrete implementation of a Port object implemented on top of + SOCK_STREAM connections. */ + +@interface TcpInPort : InPort +{ + int _port_socket; + struct sockaddr_in _listening_address; + NSMapTable *_client_sock_2_out_port; + NSMapTable *_client_sock_2_packet; +} + ++ newForReceivingFromPortNumber: (unsigned short)n; + +- (int) portNumber; +- (id) connectedOutPorts; +- (unsigned) numberOfConnectedOutPorts; + +@end + + +@interface TcpOutPort : OutPort +{ + int _port_socket; + /* This is actually the address of the listen()'ing socket of the remote + TcpInPort we are connected to, not the address of the _port_socket ivar. */ + struct sockaddr_in _remote_in_port_address; + /* This is the address of our remote peer socket. */ + struct sockaddr_in _peer_address; + /* The TcpInPort that is polling our _port_socket with select(). */ + id _polling_in_port; +} + ++ newForSendingToPortNumber: (unsigned short)n + onHost: (NSString*)hostname; +- (int) portNumber; + +@end + + +/* Holders of sent and received data. */ + +@interface TcpInPacket : InPacket +@end +@interface TcpOutPacket : OutPacket +@end + + +/* Notification Strings. */ +GS_EXPORT NSString *InPortClientBecameInvalidNotification; +GS_EXPORT NSString *InPortAcceptedClientNotification; + +#endif /* __TcpPort_h__GNUSTEP_BASE_INCLUDE */ + diff --git a/Old/TcpPort.m b/Old/TcpPort.m new file mode 100644 index 000000000..71446edc2 --- /dev/null +++ b/Old/TcpPort.m @@ -0,0 +1,1609 @@ +/* Implementation of network port object based on TCP sockets + Copyright (C) 1996, 1997 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: February 1996 + + 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. + */ + +/* Name server support and exceptions added october 1996 + by Richard Frith-Macdonald (richard@brainstorm.co.uk) + Socket I/O made non blocking. */ + +/* A strange attempt to make SOCK_STREAM sockets look like ports. The + two concepts don't fit together easily. Be prepared for a little + weirdness. */ + +/* TODO: + Change so we don't wait on incoming packet prefix. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if !defined(__WIN32__) || defined(__CYGWIN__) +#include /* for gethostname() */ +#include /* for inet_ntoa() */ +#include +#include +#include +#include + +/* For IRIX machines, which don't define this */ +#ifndef IPPORT_USERRESERVED +#define IPPORT_USERRESERVED 5000 +#endif /* IPPORT_USERRESERVED */ + +/* + * Stuff for setting the sockets into non-blocking mode. + */ +#ifdef __POSIX_SOURCE +#define NBLK_OPT O_NONBLOCK +#else +#define NBLK_OPT FNDELAY +#endif + +#define stringify_it(X) #X +#define make_gdomap_cmd(X) stringify_it(X) "/Tools/"GNUSTEP_TARGET_DIR"/gdomap &" +#define make_gdomap_err(X) "check that " stringify_it(X) "/Tools/"GNUSTEP_TARGET_DIR"/gdomap is running and owned by root." + +#endif /* !__WIN32__ */ +#include /* for memset() and strchr() */ +#if !defined(__WIN32__) || defined(__CYGWIN__) +#include +#include +#include +#include +#endif /* !__WIN32__ */ + +static int debug_tcp_port = 0; + + + + +@interface TcpPrefPacket : TcpInPacket +@end +@implementation TcpPrefPacket +@end + + +@interface NSPort (Debug) ++ (void) setDebug: (int)val; +@end + +@implementation NSPort (Debug) ++ (void) setDebug: (int)val +{ + debug_tcp_port = val; +} +@end + + + +@interface TcpInPort (Private) +- (int) _port_socket; +- (struct sockaddr_in*) _listeningSockaddr; +- (void) _addClientOutPort: p; +- (void) _connectedOutPortInvalidated: p; +- _tryToGetPacketFromReadableFD: (int)fd_index; +@end + +@interface TcpOutPort (Private) +- (int) _port_socket; +- _initWithSocket: (int)s inPort: ip; ++ _newWithAcceptedSocket: (int)s peeraddr: (struct sockaddr_in*)addr inPort: p; +- (struct sockaddr_in*) _remoteInPortSockaddr; +@end + +@interface TcpInPacket (Private) +- (int) _fillFromSocket: (int)s; ++ (void) _getPacketSize: (int*)size + andSendPort: (id*)sp + andReceivePort: (id*)rp + fromSocket: (int)s; +@end + +@interface TcpOutPacket (Private) +- (void) _writeToSocket: (int)s + withSendPort: (id)sp + withReceivePort: (id)rp + timeout: (NSTimeInterval)t; +@end + +#if 0 +/* Not currently being used; but see the comment in -sendPacket:timeout: */ + +/* TcpInStream - an object that represents an accept()'ed socket + that's being polled by a TcpInPort's select(). This object cannot + be the same as a TcpOutPort because we cannot be sure that someone + is polling the socket on the other end---unfortunately this means + that the socket's used by Tcp*Port objects are only used for sending + data in one direction. */ + +@interface TcpInStream : NSObject +{ + int _port_socket; + id _listening_in_port; +} +- initWithAcceptedSocket: (int)s inPort: p; +@end +#endif /* 0 */ + + + +extern int errno; /* For systems where it is not in the include */ + +/* + * Name - tryRead() + * Purpose - Attempt to read from a non blocking channel. + * Time out in specified time. + * If length of data is zero then just wait for + * descriptor to be readable. + * If the length is negative then attempt to + * read the absolute value of length but return + * as soon as anything is read. + * + * Return -1 on failure + * Return -2 on timeout + * Return number of bytes read + */ +static int +tryRead(int desc, int tim, unsigned char* dat, int len) +{ + struct timeval timeout; + fd_set fds; + void *to; + int rval; + int pos = 0; + time_t when = 0; + int neg = 0; + + if (len < 0) { + neg = 1; + len = -len; + } + + /* + * First time round we do a select with an instant timeout to see + * if the descriptor is already readable. + */ + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + for (;;) { + to = &timeout; + memset(&fds, '\0', sizeof(fds)); + FD_SET(desc, &fds); + + rval = select(FD_SETSIZE, &fds, 0, 0, to); + if (rval == 0) { + time_t now = time(0); + + if (when == 0) { + when = now; + } + else if (now - when >= tim) { + return(-2); /* Timed out. */ + } + else { + /* Set the timeout for a new call to select next time round + * the loop. */ + timeout.tv_sec = tim - (now - when); + timeout.tv_usec = 0; + } + } + else if (rval < 0) { + return(-1); /* Error in select. */ + } + else if (len > 0) { + rval = read(desc, &dat[pos], len - pos); + if (rval < 0) { + if (errno != EWOULDBLOCK) { + return(-1); /* Error in read. */ + } + } + else if (rval == 0) { + return(-1); /* End of file. */ + } + else { + pos += rval; + if (pos == len || neg == 1) { + return(pos); /* Read as needed. */ + } + } + } + else { + return(0); /* Not actually asked to read. */ + } + } +} + +/* + * Name - tryWrite() + * Purpose - Attempt to write to a non blocking channel. + * Time out in specified time. + * If length of data is zero then just wait for + * descriptor to be writable. + * If the length is negative then attempt to + * write the absolute value of length but return + * as soon as anything is written. + * + * Return -1 on failure + * Return -2 on timeout + * Return number of bytes written + */ +static int +tryWrite(int desc, int tim, unsigned char* dat, int len) +{ + struct timeval timeout; + fd_set fds; + void *to; + int rval; + int pos = 0; + time_t when = 0; + int neg = 0; + + if (len < 0) { + neg = 1; + len = -len; + } + + /* + * First time round we do a select with an instant timeout to see + * if the descriptor is already writable. + */ + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + for (;;) { + to = &timeout; + memset(&fds, '\0', sizeof(fds)); + FD_SET(desc, &fds); + + rval = select(FD_SETSIZE, 0, &fds, 0, to); + if (rval == 0) { + time_t now = time(0); + + if (when == 0) { + when = now; + } + else if (now - when >= tim) { + return(-2); /* Timed out. */ + } + else { + /* Set the timeout for a new call to select next time round + * the loop. */ + timeout.tv_sec = tim - (now - when); + timeout.tv_usec = 0; + } + } + else if (rval < 0) { + return(-1); /* Error in select. */ + } + else if (len > 0) { + rval = write(desc, &dat[pos], len - pos); + + if (rval <= 0) { + if (errno != EWOULDBLOCK) { + return(-1); /* Error in write. */ + } + } + else { + pos += rval; + if (pos == len || neg == 1) { + return(pos); /* Written as needed. */ + } + } + } + else { + return(0); /* Not actually asked to write. */ + } + } +} + + +/* Both TcpInPort's and TcpOutPort's are entered in this maptable. */ + +static NSMapTable *socket_2_port = NULL; + +static void +init_port_socket_2_port () +{ + if (!socket_2_port) + socket_2_port = + NSCreateMapTable (NSIntMapKeyCallBacks, + NSNonOwnedPointerMapValueCallBacks, 0); +} + + + +/* TcpInPort class - An object that represents a listen()'ing socket, + and a collection of socket's which the NSRunLoop will poll using + select(). Each of the socket's that is polled is actually held by + a TcpOutPort object. See the comments by TcpOutPort below. */ + +@implementation TcpInPort + +/* This map table is used to make sure we don't create more than one + TcpInPort listening to the same port number. */ +static NSMapTable* port_number_2_port; + ++ (void) initialize +{ + if (self == [TcpInPort class]) + { + port_number_2_port = + NSCreateMapTable (NSIntMapKeyCallBacks, + NSNonOwnedPointerMapValueCallBacks, 0); + init_port_socket_2_port (); + /* + * If SIGPIPE is not ignored, we will abort on any attempt to + * write to a pipe/socket that has been closed by the other end! + */ + signal(SIGPIPE, SIG_IGN); + } +} + +/* This is the designated initializer. + If N is zero, it will choose a port number for you. */ + ++ newForReceivingFromPortNumber: (unsigned short)n +{ + TcpInPort *p; + + /* If there already is a TcpInPort listening to this port number, + don't create a new one, just return the old one. */ + if ((p = (id) NSMapGet (port_number_2_port, (void*)((int)n)))) + { + NSAssert(p->_is_valid, NSInternalInconsistencyException); + return [p retain]; + } + + /* There isn't already a TcpInPort for this port number, so create + a new one. */ + + /* Create the port object. */ + p = [[TcpInPort alloc] init]; + + /* Create the socket. */ + p->_port_socket = socket (AF_INET, SOCK_STREAM, 0); + if (p->_port_socket < 0) + { + [p release]; + [NSException raise: NSInternalInconsistencyException + format: @"[TcpInPort +newForReceivingFromPortNumber:] socket(): %s", + strerror(errno)]; + } + + /* Register the port object according to its socket. */ + NSAssert(!NSMapGet (socket_2_port, (void*)p->_port_socket), NSInternalInconsistencyException); + NSMapInsert (socket_2_port, (void*)p->_port_socket, p); + + /* Give the socket a name using bind() and INADDR_ANY for the + machine address in _LISTENING_ADDRESS; then put the network + address of this machine in _LISTENING_ADDRESS.SIN_ADDR, so + that when we encode the address, another machine can find us. */ + { + struct hostent *hp; + NSString *hostname; + int r; + + /* Set the re-use socket option so that we don't get this socket + hanging around after we close it (or die) */ + r = 1; + setsockopt(p->_port_socket,SOL_SOCKET,SO_REUSEADDR,(char*)&r,sizeof(r)); + /* Fill in the _LISTENING_ADDRESS with the address this in port on + which will listen for connections. Use INADDR_ANY so that we + will accept connection on any of the machine network addresses; + most machine will have both an Internet address, and the + "localhost" address (i.e. 127.0.0.1) */ + p->_listening_address.sin_addr.s_addr = GSSwapHostI32ToBig (INADDR_ANY); + p->_listening_address.sin_family = AF_INET; + p->_listening_address.sin_port = GSSwapHostI16ToBig (n); + /* N may be zero, in which case bind() will choose a port number + for us. */ + if (bind (p->_port_socket, + (struct sockaddr*) &(p->_listening_address), + sizeof (p->_listening_address)) + < 0) + { + BOOL ok = NO; + /* bind() sometimes seems to fail when given a port of zero - this + * should really never happen, so we retry a few times in case the + * kernel has had a temporary brainstorm. + */ + if (n == 0) { + int count; + + for (count = 0; count < 10; count++) { + memset(&p->_listening_address, 0, sizeof(p->_listening_address)); + p->_listening_address.sin_addr.s_addr = GSSwapHostI32ToBig (INADDR_ANY); + p->_listening_address.sin_family = AF_INET; + if (bind (p->_port_socket, + (struct sockaddr*) &(p->_listening_address), + sizeof (p->_listening_address)) == 0) { + ok = YES; + break; + } + } + } + if (ok == NO) { + [p release]; + [NSException raise: NSInternalInconsistencyException + format: @"[TcpInPort +newForReceivingFromPortNumber:] bind(): %s", + strerror(errno)]; + } + } + + /* If the caller didn't specify a port number, it was chosen for us. + Here, find out what number was chosen. */ + if (!n) + /* xxx Perhaps I should do this unconditionally? */ + { + int size = sizeof (p->_listening_address); + if (getsockname (p->_port_socket, + (struct sockaddr*)&(p->_listening_address), + &size) + < 0) + { + [p release]; + [NSException raise: NSInternalInconsistencyException + format: @"[TcpInPort +newForReceivingFromPortNumber:] getsockname(): %s", + strerror(errno)]; + + } + NSAssert(p->_listening_address.sin_port, NSInternalInconsistencyException); + n = GSSwapBigI16ToHost(p->_listening_address.sin_port); + } + + /* Now change _LISTENING_ADDRESS to the specific network address of this + machine so that, when we encoded our _LISTENING_ADDRESS for a + Distributed Objects connection to another machine, they get our + unique host address that can identify us across the network. */ + hostname = [[NSHost currentHost] name]; + if (hostname == nil) + { + [p release]; + [NSException raise: NSInternalInconsistencyException + format: @"[TcpInPort +newForReceivingFromPortNumber:] no hostname"]; + } + hp = gethostbyname ([hostname cString]); + if (!hp) + hp = gethostbyname ("localhost"); + if (hp == 0) + { + NSLog(@"Unable to get IP address of '%@' or of 'localhost'", hostname); +#ifndef HAVE_INET_ATON + p->_listening_address.sin_addr.s_addr = inet_addr("127.0.0.1"); +#else + inet_aton("127.0.0.1", &p->_listening_address.sin_addr); +#endif + } + else + memcpy (&(p->_listening_address.sin_addr), hp->h_addr, hp->h_length); + } + + /* Set it up to accept connections, let 10 pending connections queue */ + /* xxx Make this "10" a class variable? */ + if (listen (p->_port_socket, 10) < 0) + { + [p release]; + [NSException raise: NSInternalInconsistencyException + format: @"[TcpInPort +newForReceivingFromPortNumber:] listen(): %s", + strerror(errno)]; + } + + /* Initialize the tables for matching socket's to out ports and packets. */ + p->_client_sock_2_out_port = + NSCreateMapTable (NSIntMapKeyCallBacks, + NSObjectMapValueCallBacks, 0); + p->_client_sock_2_packet = + NSCreateMapTable (NSIntMapKeyCallBacks, + NSNonOwnedPointerMapValueCallBacks, 0); + + /* Record the new port in TcpInPort's class table. */ + NSMapInsert (port_number_2_port, (void*)(int)n, p); + + return p; +} + ++ newForReceivingFromRegisteredName: (NSString*)name +{ + return [self newForReceivingFromRegisteredName: name fromPort: 0]; +} + ++ newForReceivingFromRegisteredName: (NSString*)name + fromPort: (int)portn +{ + TcpInPort* p = [self newForReceivingFromPortNumber: portn]; + + if (p) { + [[NSPortNameServer systemDefaultPortNameServer] registerPort: p + forName: name]; + } + return p; +} + ++ newForReceiving +{ + return [self newForReceivingFromPortNumber: 0]; +} + +- (id) connectedOutPorts +{ + NSMapEnumerator me = NSEnumerateMapTable (_client_sock_2_out_port); + int count = NSCountMapTable (_client_sock_2_out_port); + int sock; + id out_port; + id out_ports[count]; + int i; + for (i = 0; + NSNextMapEnumeratorPair (&me, (void*)&sock, (void*)&out_port); + i++) + out_ports[i] = out_port; + return [NSArray arrayWithObjects: out_ports count: count]; +} + +- (unsigned) numberOfConnectedOutPorts +{ + return NSCountMapTable (_client_sock_2_out_port); +} + +- (struct sockaddr_in*) _listeningSockaddr +{ + NSAssert(_is_valid, NSInternalInconsistencyException); + return &_listening_address; +} + + +/* Read some data from FD; if we read enough to complete a packet, + return the packet. Otherwise, keep the partially read packet in + _CLIENT_SOCK_2_PACKET. */ + +- _tryToGetPacketFromReadableFD: (int)fd_index +{ + if (fd_index == _port_socket) + { + /* This is a connection request on the original listen()'ing socket. */ + int new; + int size; + int rval; + volatile id op; + struct sockaddr_in clientname; + + size = sizeof (clientname); + new = accept (_port_socket, (struct sockaddr*)&clientname, &size); + if (new < 0) + { + [NSException raise: NSInternalInconsistencyException + format: @"[TcpInPort receivePacketWithTimeout:] accept(): %s", + strerror(errno)]; + } + /* + * Code to ensure that new socket is non-blocking. + */ + if ((rval = fcntl(new, F_GETFL, 0)) >= 0) { + rval |= NBLK_OPT; + if (fcntl(new, F_SETFL, rval) < 0) { + close(new); + [NSException raise: NSInternalInconsistencyException + format: @"[TcpInPort receivePacketWithTimeout:] fcntl(SET): %s", + strerror(errno)]; + } + } + else { + close(new); + [NSException raise: NSInternalInconsistencyException + format: @"[TcpInPort receivePacketWithTimeout:] fcntl(GET): %s", + strerror(errno)]; + } + op = [TcpOutPort _newWithAcceptedSocket: new + peeraddr: &clientname + inPort: self]; + [self _addClientOutPort: op]; + if (debug_tcp_port) + NSLog(@"%s: Accepted connection from\n %@.\n", + object_get_class_name (self), [op description]); + [[NSNotificationCenter defaultCenter] + postNotificationName: InPortAcceptedClientNotification + object: self + userInfo: op]; + [op release]; + } + else + { + /* Data has arrived on an already-connected socket. */ + TcpInPacket *packet; + int remaining; + + /* See if there is already a InPacket object waiting for + more data from this socket. */ + if (!(packet = NSMapGet (_client_sock_2_packet, + (void*)fd_index))) + { + /* This is the beginning of a new packet on this socket. + Create a new InPacket object for gathering the data. */ + + /* First, get the packet size and reply port, (which is + encoded in the first few bytes of the stream). */ + int packet_size; + id send_port; + id receive_port; + [TcpInPacket _getPacketSize: &packet_size + andSendPort: &send_port + andReceivePort: &receive_port + fromSocket: fd_index]; + /* If we got an EOF when trying to read the packet prefix, + invalidate the port, and keep on waiting for incoming + data on other sockets. */ + if (packet_size == EOF) + { + [(id) NSMapGet (_client_sock_2_out_port, (void*)fd_index) + invalidate]; + return nil; + } + else + { + packet = [[TcpInPacket alloc] + initForReceivingWithCapacity: packet_size + receivingInPort: send_port + replyOutPort: receive_port]; + if (packet == nil) + [NSException raise: NSInternalInconsistencyException + format: @"[TcpInPort _tryToGetPacketFromReadableFD:" + @" - failed to create incoming packet"]; + NSMapInsert(_client_sock_2_packet,(void*)fd_index,(void*)packet); + } + /* The packet has now been created with correct capacity */ + } + + /* Suck bytes from the socket into the packet; find out + how many more bytes are needed before packet will be + complete. */ + remaining = [packet _fillFromSocket: (int)fd_index]; + if (remaining == EOF) + { + /* We got an EOF when trying to read packet data; + release the packet and invalidate the corresponding + port, and keep on waiting for incoming data on + other sockets. */ + NSMapRemove(_client_sock_2_packet, (void*)fd_index); + [packet release]; + [(id) NSMapGet (_client_sock_2_out_port, (void*)fd_index) + invalidate]; + return nil; + } + else if (remaining == 0) + { + /* No bytes are remaining to be read for this packet; + the packet is complete; return it. */ + NSAssert(packet && [packet class], NSInternalInconsistencyException); + NSMapRemove(_client_sock_2_packet, (void*)fd_index); + if (debug_tcp_port > 1) + NSLog(@"%s: Read from socket %d\n", + object_get_class_name (self), fd_index); + return packet; + } + } + return nil; +} + + +/* Dealing with the relationship to a NSRunLoop. */ + +/* The NSRunLoop will send us this message just before it's about to call + select(). It is asking us to fill fds[] in with the sockets on which + it should listen. *count should be set to the number of sockets we + put in the array. */ + +- (void) getFds: (int*)fds count: (int*)count +{ + NSMapEnumerator me; + int sock; + id out_port; + + /* Make sure there is enough room in the provided array. */ + NSAssert(*count > NSCountMapTable (_client_sock_2_out_port), NSInternalInconsistencyException); + + /* Put in our listening socket. */ + *count = 0; + fds[(*count)++] = _port_socket; + + /* Enumerate all our client sockets, and put them in. */ + me = NSEnumerateMapTable (_client_sock_2_out_port); + while (NSNextMapEnumeratorPair (&me, (void*)&sock, (void*)&out_port)) + fds[(*count)++] = sock; +} + +/* This is called by the NSRunLoop when select() says the FD is ready + for reading. */ + +#include +- (void) receivedEvent: (void*)data + type: (RunLoopEventType)type + extra: (void*)extra + forMode: (NSString*)mode +{ + id arp = [NSAutoreleasePool new]; + id packet; + + NSAssert(type == ET_RPORT, NSInvalidArgumentException); + + packet = [self _tryToGetPacketFromReadableFD: (int)extra]; + if (packet) { + [_packet_invocation invokeWithObject: packet]; + } + [arp release]; + return; +} + +- (NSDate*)timedOutEvent: (void*)data + type: (RunLoopEventType)type + forMode: (NSString*)mode +{ + return nil; +} + + +/* Adding an removing client sockets (ports). */ + +/* Add and removing out port's from the collection of connections we handle. */ + +- (void) _addClientOutPort: p +{ + int s = [p _port_socket]; + + NSAssert(_is_valid, NSInternalInconsistencyException); + /* Make sure it hasn't already been added. */ + NSAssert(!NSMapGet (_client_sock_2_out_port, (void*)s), NSInternalInconsistencyException); + + /* Add it, and put its socket in the set of file descriptors we poll. */ + NSMapInsert (_client_sock_2_out_port, (void*)s, p); +} + +/* Called by an OutPort in its -invalidate method. */ +- (void) _connectedOutPortInvalidated: p +{ + id packet; + int s = [p _port_socket]; + + NSAssert(_is_valid, NSInternalInconsistencyException); + if (debug_tcp_port) + NSLog(@"%s: Closed connection from\n %@\n", + object_get_class_name (self), [p description]); + + packet = NSMapGet (_client_sock_2_packet, (void*)s); + if (packet) + { + NSMapRemove (_client_sock_2_packet, (void*)s); + [packet release]; + } + NSMapRemove (_client_sock_2_out_port, (void*)s); +/* + * This method is all wrong - messes up badly when called from + * an OutPort which is deallocating itsself. + */ +#if 0 + /* xxx Should this be earlier, so that the notification recievers + can still use _client_sock_2_out_port before the out port P is removed? */ + [[NSNotificationCenter defaultCenter] + postNotificationName: InPortClientBecameInvalidNotification + object: self + userInfo: p]; +#endif +} + +- (int) _port_socket +{ + return _port_socket; +} + +- (int) portNumber +{ + return (int) GSSwapBigI16ToHost (_listening_address.sin_port); +} + +- (void) invalidate +{ + if (_is_valid) + { + NSMapEnumerator me = NSEnumerateMapTable (_client_sock_2_out_port); + int count = NSCountMapTable (_client_sock_2_out_port); + id out_port; + int sock; + id out_ports[count]; + int i; + + /* These are here, and not in -dealloc, to prevent + +newForReceivingFromPortNumber: from returning invalid sockets. */ + NSMapRemove (socket_2_port, (void*)_port_socket); + NSMapRemove (port_number_2_port, + (void*)(int)GSSwapBigI16ToHost(_listening_address.sin_port)); + + for (i = 0; + NSNextMapEnumeratorPair (&me, (void*)&sock, (void*)&out_port); + i++) + out_ports[i] = out_port; + for (i = 0; i < count; i++) + { + /* This will call [self _invalidateConnectedOutPort: for each. */ + [out_ports[i] invalidate]; + } + NSAssert(!NSCountMapTable (_client_sock_2_out_port), NSInternalInconsistencyException); + + /* xxx Perhaps should delay this close() to keep another port from + getting it. This may help Connection invalidation confusion. + However, then the process might run out of FD's if the close() + was delayed too long. */ + if (_port_socket > 0) + { +#if !defined(__CYGWIN__) && defined(__WIN32__) + closesocket (_port_socket); +#else + close (_port_socket); +#endif /* __WIN32__ */ + } + + /* This also posts a NSPortDidBecomeInvalidNotification. */ + [super invalidate]; + } +} + +- (void) dealloc +{ + [self invalidate]; + NSFreeMapTable (_client_sock_2_out_port); + NSFreeMapTable (_client_sock_2_packet); + [super dealloc]; +} + +- (void) checkConnection +{ + [self notImplemented: _cmd]; +} + ++ (Class) outPacketClass +{ + return [TcpOutPacket class]; +} + +- (Class) outPacketClass +{ + return [TcpOutPacket class]; +} + +- description +{ + return [NSString + stringWithFormat: @"%s%c0x%x port %hd socket %d", + object_get_class_name (self), + _is_valid ? ' ' : '-', + (unsigned)self, + GSSwapBigI16ToHost(_listening_address.sin_port), + _port_socket]; +} + +- (Class) classForPortCoder +{ + /* Make sure that Connection's always send us bycopy, not a Proxy class. + Also, encode a "send right" (ala Mach), not the "receive right". */ + return [TcpOutPort class]; +} +- replacementObjectForPortCoder: aRmc +{ + return self; +} + +- (void) encodeWithCoder: aCoder +{ + NSAssert(_is_valid, NSInternalInconsistencyException); + /* We are actually encoding a "send right" (ala Mach), + not a receive right. + These values must match those expected by [TcpOutPort +newWithCoder] */ + /* Encode these at bytes, not as C-variables, because they are + already in "network byte-order". */ + [aCoder encodeBytes: &_listening_address.sin_port + count: sizeof (_listening_address.sin_port) + withName: @"socket number"]; + [aCoder encodeBytes: &_listening_address.sin_addr.s_addr + count: sizeof (_listening_address.sin_addr.s_addr) + withName: @"inet address"]; +} + ++ newWithCoder: aCoder +{ + /* An InPort cannot be created by decoding, only OutPort's. */ + [self shouldNotImplement: _cmd]; + return nil; +} + +@end + + + +/* TcpOutPort - An object that represents a connection to a remote + host. Although it is officially an "Out" Port, we actually receive + data on the socket that is this object's `_port_socket' ivar; TcpInPort + takes care of this. */ + +@implementation TcpOutPort + +/* A collection of all the all the TcpOutPort's, keyed by their id. */ +/* xxx This would be more efficient as a void* array instead of a map table. */ +static NSMapTable *out_port_bag = NULL; + ++ (void) initialize +{ + if (self == [TcpOutPort class]) + { + init_port_socket_2_port (); + out_port_bag = NSCreateMapTable (NSNonOwnedPointerMapKeyCallBacks, + NSNonOwnedPointerMapValueCallBacks, 0); + /* + * If SIGPIPE is not ignored, we will abort on any attempt to + * write to a pipe/socket that has been closed by the other end! + */ + signal(SIGPIPE, SIG_IGN); + } +} + +#if 0 +/* Not needed unless we use TcpInStream objects. */ ++ (void) checkForInvalidatedPorts {} +#endif + + +/* This is the designated creator. + + If SOCK is 0, then SOCKADDR must be non-NULL. It is the address of + the socket on which the remote TcpInPort is listen()'ing. Note + that it is *not* the address of the TcpOutPort's + getsockname(_port_socket,...), and it is not the address of the + TcpOutPort's getpeername(_port_socket,...). + + SOCK can be either an already-created socket, or 0, in which case a + socket will be created. + + If SOCK is non-zero, and SOCKADDR is non-zero, then this is a request + to set the _remote_in_port_address ivar of a pre-existing TcpOutPort + instance. In this case the IP argument must match the _polling_in_port + of the instance. + + IP can be either an already-created InPort object, or nil. */ + ++ newForSendingToSockaddr: (struct sockaddr_in*)sockaddr + withAcceptedSocket: (int)sock + pollingInPort: ip +{ + TcpOutPort *p; + + /* See if there already exists a port for this sockaddr; + if so, just return it. However, there is no need to do this + if SOCK already holds an accept()'ed socket---in that case we + should always create a new OutPort object. */ + if (!sock) + { + NSMapEnumerator me = NSEnumerateMapTable (out_port_bag); + void *k; + + NSAssert(sockaddr, NSInternalInconsistencyException); + while (NSNextMapEnumeratorPair (&me, &k, (void**)&p)) + { + /* xxx Do I need to make sure connectedInPort is the same too? */ + /* xxx Come up with a way to do this with a hash key, not a list. */ + if ((sockaddr->sin_port + == p->_remote_in_port_address.sin_port) + && (sockaddr->sin_addr.s_addr + == p->_remote_in_port_address.sin_addr.s_addr)) + /* Assume that sin_family is equal. Using memcmp() doesn't + work because sin_zero's may differ. */ + { + NSAssert(p->_is_valid, NSInternalInconsistencyException); + return [p retain]; + } + } + } + /* xxx When the AcceptedSocket-style OutPort gets its + _remote_in_port_address set, we should make sure that there isn't + already an OutPort with that address. */ + + /* See if there already exists a TcpOutPort object with ivar _port_socket + equal to SOCK. If there is, and if sockaddr is non-null, this + call may be a request to set the TcpOutPort's _remote_in_port_address + ivar. */ + if (sock && (p = NSMapGet (socket_2_port, (void*)sock))) + { + NSAssert([p isKindOfClass: [TcpOutPort class]], NSInternalInconsistencyException); + if (sockaddr) + { + /* Make sure the address we're setting it to is non-zero. */ + NSAssert(sockaddr->sin_port, NSInternalInconsistencyException); + + /* See if the _remote_in_port_address is already set */ + if (p->_remote_in_port_address.sin_family) + { +#if 0 + /* It is set; make sure no one is trying to change it---that + isn't allowed. */ + if ((p->_remote_in_port_address.sin_port + != sockaddr->sin_port) + || (p->_remote_in_port_address.sin_addr.s_addr + != sockaddr->sin_addr.s_addr)) + [self error:"Can't change reply port of an out port once set"]; +#else + if ((p->_remote_in_port_address.sin_port + != sockaddr->sin_port) + || (p->_remote_in_port_address.sin_addr.s_addr + != sockaddr->sin_addr.s_addr)) + { +// NSString *od = [p description]; + + NSMapRemove (out_port_bag, (void*)p); + memcpy (&(p->_remote_in_port_address), + sockaddr, + sizeof (p->_remote_in_port_address)); + NSMapInsert (out_port_bag, (void*)p, (void*)p); +/* + NSLog(@"Out port changed from %@ to %@\n", od, + [p description]); +*/ + } +#endif + } + else + { + /* It wasn't set before; set it by copying it in. */ + memcpy (&(p->_remote_in_port_address), + sockaddr, + sizeof (p->_remote_in_port_address)); + if (debug_tcp_port) + NSLog(@"TcpOutPort setting remote address\n%@\n", + [self description]); + } + } + if (p) + { + NSAssert(p->_is_valid, NSInternalInconsistencyException); + return [p retain]; + } + } + + /* There isn't already an in port for this sockaddr or sock, + so create a new port. */ + p = [[self alloc] init]; + + /* Set its socket. */ + if (sock) + p->_port_socket = sock; + else + { + p->_port_socket = socket (AF_INET, SOCK_STREAM, 0); + if (p->_port_socket < 0) + { + [p release]; + [NSException raise: NSInternalInconsistencyException + format: @"[TcpInPort newForSendingToSockaddr:...] socket(): %s", + strerror(errno)]; + } + } + + /* Register which InPort object will listen to replies from our messages. + This may be nil, in which case it can get set later in -sendPacket... */ + p->_polling_in_port = ip; + + /* Set the port's address. */ + if (sockaddr) + { + NSAssert(sockaddr->sin_port, NSInternalInconsistencyException); + memcpy (&(p->_remote_in_port_address), sockaddr, sizeof(*sockaddr)); + } + else + { + /* Else, _remote_in_port_address will remain as zero's for the + time being, and may get set later by calling + +newForSendingToSockaddr.. with a non-zero socket, and a + non-NULL sockaddr. */ + memset (&(p->_remote_in_port_address), '\0', sizeof(*sockaddr)); + } + + /* xxx Do I need to bind(_port_socket) to this address? I don't think so. */ + + /* Connect the socket to its destination, (if it hasn't been done + already by a previous accept() call. */ + if (!sock) { + int rval; + + NSAssert(p->_remote_in_port_address.sin_family, NSInternalInconsistencyException); + + if (connect (p->_port_socket, + (struct sockaddr*)&(p->_remote_in_port_address), + sizeof(p->_remote_in_port_address)) < 0) + { + [p release]; + [NSException raise: NSInternalInconsistencyException + format: @"[TcpInPort newForSendingToSockaddr:...] connect(): %s", + strerror(errno)]; + } + + /* + * Ensure the socket is non-blocking. + */ + if ((rval = fcntl(p->_port_socket, F_GETFL, 0)) >= 0) { + rval |= NBLK_OPT; + if (fcntl(p->_port_socket, F_SETFL, rval) < 0) { + [p release]; + [NSException raise: NSInternalInconsistencyException + format: @"[TcpInPort newForSendingToSockaddr:...] fcntl(SET): %s", + strerror(errno)]; + } + } + else { + [p release]; + [NSException raise: NSInternalInconsistencyException + format: @"[TcpInPort newForSendingToSockaddr:...] fcntl(GET): %s", + strerror(errno)]; + } + + } + + /* Put it in the shared socket->port map table. */ + NSAssert(!NSMapGet (socket_2_port, (void*)p->_port_socket), NSInternalInconsistencyException); + NSMapInsert (socket_2_port, (void*)p->_port_socket, p); + + /* Put it in TcpOutPort's registry. */ + NSMapInsert (out_port_bag, (void*)p, (void*)p); + + return p; +} + ++ newForSendingToPortNumber: (unsigned short)n + onHost: (NSString*)hostname +{ + struct hostent *hp; + const char *host_cstring; + struct sockaddr_in addr; + + /* Look up the hostname. */ + if (!hostname || ![hostname length]) + { + hostname = [[NSHost currentHost] name]; + if (hostname == nil) + { + NSLog(@"No local host set upt!"); + return nil; + } + } + host_cstring = [hostname cString]; + hp = gethostbyname ((char*)host_cstring); + if (!hp) + [self error: "unknown host: \"%s\"", host_cstring]; + + /* Get the sockaddr_in address. */ + memcpy (&addr.sin_addr, hp->h_addr, hp->h_length); + addr.sin_family = AF_INET; + addr.sin_port = GSSwapHostI16ToBig (n); + + return [self newForSendingToSockaddr: &addr + withAcceptedSocket: 0 + pollingInPort: nil]; +} + ++ newForSendingToRegisteredName: (NSString*)name + onHost: (NSString*)hostname +{ + id c; + + c = [[NSPortNameServer systemDefaultPortNameServer] portForName: name + onHost: hostname]; + return [c retain]; +} + ++ _newWithAcceptedSocket: (int)s + peeraddr: (struct sockaddr_in*)peeraddr + inPort: p +{ +#if 0 + struct sockaddr_in addr; + int size = sizeof (struct sockaddr_in); + + /* Get the sockaddr. */ + if (getpeername (s, (struct sockaddr*)&addr, &size) < 0) + { + [NSException raise: NSInternalInconsistencyException + format: @"[TcpInPort newWithAcceptedSocket:] getsockname(): %s", + strerror(errno)]; + } + NSAssert(size == sizeof (struct sockaddr_in), NSInternalInconsistencyException); + /* xxx Perhaps I have to get peer name here!! */ + NSAssert(GSSwapBigI16ToHost(addr.sin_port) != [p portNumber], NSInternalInconsistencyException); +#elif 0 + struct sockaddr_in in_port_address; + c = read (s, &in_port_address, sizeof(struct sockaddr_in)); +#endif + + return [self newForSendingToSockaddr: NULL + withAcceptedSocket: s + pollingInPort: p]; +} + +- (struct sockaddr_in*) _remoteInPortSockaddr +{ + return &_remote_in_port_address; +} + +- (BOOL) sendPacket: packet timeout: (NSTimeInterval)timeout +{ + id reply_port = [packet replyInPort]; + + NSAssert(_is_valid, NSInternalInconsistencyException); + + /* If the socket of this TcpOutPort isn't already being polled + for incoming data by a TcpInPort, and if the packet's REPLY_PORT + is non-nil, then set up this TcpOutPort's socket to be polled by + the REPLY_PORT. Once a TcpOutPort is associated with a particular + TcpInPort, it is permanantly associated with that InPort; it cannot + be re-associated with another TcpInPort later. + The creation and use of TcpInStream objects could avoid this + restriction; see the note about them at the top of this file. */ + if (_polling_in_port == nil && reply_port != nil) + { + _polling_in_port = reply_port; + [_polling_in_port _addClientOutPort: self]; + } + else if (_polling_in_port != reply_port) + [self error: "Instances of %s can't change their reply port once set.", + object_get_class_name (self)]; + /* Creating TcpInStream objects, and separating them from + TcpOutPort's would fix this restriction. However, it would + also have the disadvantage of using all socket's only for + sending data one-way, and creating twice as many socket's for + two-way exchanges. */ + + /* Ask the packet to write it's bytes to the socket. + The TcpPacket will also write a prefix, indicating the packet size + and the port addresses. If REPLY_PORT is nil, the third argument + to this call with be NULL, and + __writeToSocket:withSendPort:withReceivePort:timeout: + will know that there is no reply port. */ + [packet _writeToSocket: _port_socket + withSendPort: self + withReceivePort: reply_port + timeout: timeout]; + return YES; +} + +- (int) _port_socket +{ + return _port_socket; +} + +- (int) portNumber +{ + return (int) GSSwapBigI16ToHost (_remote_in_port_address.sin_port); +} + +- (void) close +{ + [self invalidate]; +} + +- (void) invalidate +{ + if (_is_valid) + { + id port = _polling_in_port; + + [self retain]; + _polling_in_port = nil; + + /* This is here, and not in -dealloc, because invalidated + but not dealloc'ed ports should not be returned from + the out_port_bag in +newForSendingToSockaddr:... */ + NSMapRemove (out_port_bag, (void*)self); + /* This is here, and not in -dealloc, because invalidated + but not dealloc'ed ports should not be returned from + the socket_2_port in +newForSendingToSockaddr:... */ + NSMapRemove (socket_2_port, (void*)_port_socket); + + [port _connectedOutPortInvalidated: self]; + + /* This also posts a NSPortDidBecomeInvalidNotification. */ + [super invalidate]; + + /* xxx Perhaps should delay this close() to keep another port from + getting it. This may help Connection invalidation confusion. */ + if (_port_socket > 0) + { +#if !defined(__CYGWIN__) && defined(__WIN32__) + if (closesocket (_port_socket) < 0) +#else + if (close (_port_socket) < 0) +#endif /* __WIN32 */ + { + [NSException raise: NSInternalInconsistencyException + format: @"[TcpOutPort -invalidate:] close(): %s", + strerror(errno)]; + } + } + [self release]; + } +} + +- (void) dealloc +{ + [self invalidate]; + [super dealloc]; +} + +- classForPortCoder +{ + /* Make sure that Connection's always send us bycopy, + i.e. as our own class, not a Proxy class. */ + return [self class]; +} + +- replacementObjectForPortCoder: aRmc +{ + /* Make sure that Connection's always send us bycopy, + i.e. as our own class, not a Proxy class. */ + return self; +} + +- (Class) outPacketClass +{ + return [TcpOutPacket class]; +} + ++ (Class) outPacketClass +{ + return [TcpOutPacket class]; +} + +- description +{ + return [NSString + stringWithFormat: @"%s%c0x%x host %s port %hd socket %d", + object_get_class_name (self), + _is_valid ? ' ' : '-', + (unsigned)self, + inet_ntoa (_remote_in_port_address.sin_addr), + GSSwapBigI16ToHost(_remote_in_port_address.sin_port), + _port_socket]; +} + +- (void) encodeWithCoder: aCoder +{ + NSAssert(_is_valid, NSInternalInconsistencyException); + NSAssert(!_polling_in_port + || (GSSwapBigI16ToHost(_remote_in_port_address.sin_port) + != [_polling_in_port portNumber]), NSInternalInconsistencyException); + /* Encode these at bytes, not as C-variables, because they are + already in "network byte-order". */ + [aCoder encodeBytes: &_remote_in_port_address.sin_port + count: sizeof (_remote_in_port_address.sin_port) + withName: @"socket number"]; + [aCoder encodeBytes: &_remote_in_port_address.sin_addr.s_addr + count: sizeof (_remote_in_port_address.sin_addr.s_addr) + withName: @"inet address"]; + if (debug_tcp_port) + NSLog(@"TcpOutPort encoded port %hd host %s\n", + GSSwapBigI16ToHost(_remote_in_port_address.sin_port), + inet_ntoa (_remote_in_port_address.sin_addr)); +} + ++ newWithCoder: aCoder +{ + struct sockaddr_in addr; + + addr.sin_family = AF_INET; + [aCoder decodeBytes: &addr.sin_port + count: sizeof (addr.sin_port) + withName: NULL]; + [aCoder decodeBytes: &addr.sin_addr.s_addr + count: sizeof (addr.sin_addr.s_addr) + withName: NULL]; + if (debug_tcp_port) + NSLog(@"TcpOutPort decoded port %hd host %s\n", + GSSwapBigI16ToHost(addr.sin_port), + inet_ntoa (addr.sin_addr)); + return [TcpOutPort newForSendingToSockaddr: &addr + withAcceptedSocket: 0 + pollingInPort: nil]; +} + +@end + + +/* In and Out Packet classes. */ + +#define PREFIX_LENGTH_TYPE gsu32 +#define PREFIX_LENGTH_SIZE sizeof (PREFIX_LENGTH_TYPE) +#define PREFIX_ADDRESS_TYPE struct sockaddr_in +#define PREFIX_ADDRESS_SIZE sizeof (PREFIX_ADDRESS_TYPE) +#define PREFIX_SP_OFF PREFIX_LENGTH_SIZE +#define PREFIX_RP_OFF (PREFIX_LENGTH_SIZE + PREFIX_ADDRESS_SIZE) +#define PREFIX_SIZE (PREFIX_LENGTH_SIZE + 2*PREFIX_ADDRESS_SIZE) + +@implementation TcpInPacket + ++ (void) _getPacketSize: (int*)packet_size + andSendPort: (id*)sp + andReceivePort: (id*)rp + fromSocket: (int)s +{ + char prefix_buffer[PREFIX_SIZE]; + int c; + + c = tryRead (s, 3, prefix_buffer, PREFIX_SIZE); + if (c <= 0) + { + *packet_size = EOF; + *sp = nil; + *rp = nil; + return; + } + if (c != PREFIX_SIZE) + { + /* Was: [self error: "Failed to get packet prefix from socket."]; */ + /* xxx Currently treating this the same as EOF, but perhaps + we should treat it differently. */ + fprintf (stderr, "[%s %s]: Got %d chars instead of full prefix\n", + class_get_class_name (self), sel_get_name (_cmd), c); + *packet_size = EOF; + *sp = nil; + *rp = nil; + return; + } + + /* *size is the number of bytes in the packet, not including + the PREFIX_SIZE-byte header. */ + *packet_size = GSSwapBigI32ToHost (*(PREFIX_LENGTH_TYPE*) prefix_buffer); + NSAssert(packet_size, NSInternalInconsistencyException); + + /* If the reply address is non-zero, and the TcpOutPort for this socket + doesn't already have its _address ivar set, then set it now. */ + { + struct sockaddr_in addr; + + /* Use memcpy instead of simply casting the pointer because + some systems fail to do the cast correctly (due to alignment issues?) */ + + /* + * Get the senders send port (our receive port) + */ + memcpy (&addr, prefix_buffer + PREFIX_SP_OFF, sizeof (typeof (addr))); + if (addr.sin_family) + { + gsu16 pnum = GSSwapBigI16ToHost(addr.sin_port); + + *sp = [TcpInPort newForReceivingFromPortNumber: pnum]; + [(*sp) autorelease]; + } + else + *sp = nil; + + /* + * Now get the senders receive port (our send port) + */ + memcpy (&addr, prefix_buffer + PREFIX_RP_OFF, sizeof (typeof (addr))); + if (addr.sin_family) + { + *rp = [TcpOutPort newForSendingToSockaddr: &addr + withAcceptedSocket: s + pollingInPort: *sp]; + [(*rp) autorelease]; + } + else + *rp = nil; + } +} + +- (int) _fillFromSocket: (int)s +{ + int c; + int remaining; + + remaining = [data length] - prefix - eof_position; + c = tryRead(s, 1, [data mutableBytes] + prefix + eof_position, -remaining); + if (c <= 0) { + return EOF; + } + eof_position += c; + return remaining - c; +} + +@end + +@implementation TcpOutPacket + ++ (unsigned) prefixSize +{ + return PREFIX_SIZE; +} + +- (void) _writeToSocket: (int)s + withSendPort: (id)sp + withReceivePort: (id)rp + timeout: (NSTimeInterval)timeout +{ + struct sockaddr_in *addr; + int c; + + if (debug_tcp_port > 1) + NSLog(@"%s: Write to socket %d\n", object_get_class_name (self), s); + + /* Put the packet size in the first four bytes of the packet. */ + NSAssert(prefix == PREFIX_SIZE, NSInternalInconsistencyException); + *(PREFIX_LENGTH_TYPE*)[data mutableBytes] = GSSwapHostI32ToBig(eof_position); + + addr = [sp _remoteInPortSockaddr]; + /* Put the sockaddr_in for replies in the next bytes of the prefix + region. If there is no reply address specified, fill it with zeros. */ + if (addr) + /* Do this memcpy instead of simply casting the pointer because + some systems fail to do the cast correctly (due to alignment issues?) */ + memcpy ([data mutableBytes]+PREFIX_SP_OFF, addr, PREFIX_ADDRESS_SIZE); + else + memset ([data mutableBytes]+PREFIX_SP_OFF, 0, PREFIX_ADDRESS_SIZE); + + addr = [rp _listeningSockaddr]; + /* Put the sockaddr_in for the destination in the next bytes of the prefix + region. If there is no destination address specified, fill with zeros. */ + if (addr) + /* Do this memcpy instead of simply casting the pointer because + some systems fail to do the cast correctly (due to alignment issues?) */ + memcpy ([data mutableBytes]+PREFIX_RP_OFF, addr, PREFIX_ADDRESS_SIZE); + else + memset ([data mutableBytes]+PREFIX_RP_OFF, 0, PREFIX_ADDRESS_SIZE); + + /* Write the packet on the socket. */ + c = tryWrite (s, (int)timeout, (unsigned char*)[data bytes], prefix + eof_position); + if (c == -2) { + [NSException raise: NSPortTimeoutException + format: @"[TcpOutPort -_writeToSocket:] write() timed out"]; + } + else if (c < 0) { + [NSException raise: NSInternalInconsistencyException + format: @"[TcpOutPort -_writeToSocket:] write(): %s", + strerror(errno)]; + } + if (c != prefix + eof_position) { + [NSException raise: NSInternalInconsistencyException + format: @"[TcpOutPort -_writeToSocket:] partial write(): %s", + strerror(errno)]; + } +} + +@end diff --git a/Old/TextCStream.h b/Old/TextCStream.h new file mode 100644 index 000000000..ff01157db --- /dev/null +++ b/Old/TextCStream.h @@ -0,0 +1,34 @@ +/* Interface for GNU Objective-C text stream object for use serializing + Copyright (C) 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Written: Jan 1996 + + 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 __TextCStream_h_GNUSTEP_BASE_INCLUDE +#define __TextCStream_h_GNUSTEP_BASE_INCLUDE + +#include +#include + +@interface TextCStream : CStream + +@end + +#endif /* __TextCStream_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/TextCStream.m b/Old/TextCStream.m new file mode 100644 index 000000000..808614d27 --- /dev/null +++ b/Old/TextCStream.m @@ -0,0 +1,421 @@ +/* Implementation of GNU Objective-C text stream object for use serializing + Copyright (C) 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Written: Jan 1996 + + 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. + */ + +#include +#include +#include +#include +#include +#include + +#define DEFAULT_FORMAT_VERSION 0 + +static BOOL debug_textcoder = NO; + +@implementation TextCStream + + +/* Encoding/decoding C values */ + +#define XSTR(s) STR(s) +#define STR(s) #s + +#define ATXSTR(s) ATSTR(s) +#define ATSTR(s) @#s + +#define ROUND(V, A) \ + ({ typeof(V) __v=(V); typeof(A) __a=(A); \ + __a*((__v+__a-1)/__a); }) + +#define ENCODER_FORMAT(TYPE, CONVERSION) \ +@"%*s<%s> (" ATXSTR(TYPE) @") = %" ATXSTR(CONVERSION) @"\n" + +- (void) encodeValueOfCType: (const char*) type + at: (const void*) d + withName: (NSString*) name; +{ + if (!type) + [NSException raise:NSInvalidArgumentException format:@"type is NULL"]; + + NSAssert(*type != '@', @"tried to encode an \"ObjC\" type"); + NSAssert(*type != '^', @"tried to encode an \"ObjC\" type"); + NSAssert(*type != ':', @"tried to encode an \"ObjC\" type"); + + if (!name || [name length] == 0) + name = @"Anonymous"; + switch (*type) + { + case _C_LNG: + [stream writeFormat:@"%*s<%s> (long) = %ld\n", + indentation, "", [name cString], *(long*)d]; + break; + case _C_ULNG: + [stream writeFormat:@"%*s<%s> (unsigned long) = %lu\n", + indentation, "", [name cString], *(unsigned long*)d]; + break; + case _C_INT: + [stream writeFormat:@"%*s<%s> (int) = %d\n", + indentation, "", [name cString], *(int*)d]; + break; + case _C_UINT: + [stream writeFormat:@"%*s<%s> (unsigned int) = %u\n", + indentation, "", [name cString], *(unsigned int*)d]; + break; + case _C_SHT: + [stream writeFormat:@"%*s<%s> (short) = %d\n", + indentation, "", [name cString], (int)*(short*)d]; + break; + case _C_USHT: + [stream writeFormat:@"%*s<%s> (unsigned short) = %u\n", + indentation, "", [name cString], + (unsigned)*(unsigned short*)d]; + break; + case _C_CHR: + [stream writeFormat:@"%*s<%s> (char) = %c (0x%x)\n", + indentation, "", [name cString], + *(char*)d, (unsigned)*(char*)d]; + break; + case _C_UCHR: + [stream writeFormat:@"%*s<%s> (unsigned char) = 0x%x\n", + indentation, "", [name cString], + (unsigned)*(unsigned char*)d]; + break; + case _C_FLT: + [stream writeFormat:@"%*s<%s> (float) = %g\n", + indentation, "", [name cString], *(float*)d]; + break; + case _C_DBL: + [stream writeFormat:@"%*s<%s> (double) = %g\n", + indentation, "", [name cString], *(double*)d]; + break; + case _C_CHARPTR: + [stream writeFormat:@"%*s<%s> (char*) = \"%s\"\n", + indentation, "", [name cString], *(char**)d]; + break; + case _C_ARY_B: + { + int len = atoi (type+1); /* xxx why +1 ? */ + int offset; + + while (isdigit(*++type)); + offset = objc_sizeof_type(type); + [self encodeName:name]; + [self encodeIndent]; + while (len-- > 0) + { + /* Change this so we don't re-write type info every time. */ + [self encodeValueOfCType:type + at:d + withName:@"array component"]; + ((char*)d) += offset; + } + [self encodeUnindent]; + break; + } + case _C_STRUCT_B: + { + int acc_size = 0; + int align; + + while (*type != _C_STRUCT_E && *type++ != '='); /* skip "=" */ + [self encodeName:name]; + [self encodeIndent]; + while (*type != _C_STRUCT_E) + { + align = objc_alignof_type (type); /* pad to alignment */ + acc_size = ROUND (acc_size, align); + [self encodeValueOfCType:type + at:((char*)d)+acc_size + withName:@"structure component"]; + acc_size += objc_sizeof_type (type); /* add component size */ + type = objc_skip_typespec (type); /* skip component */ + } + [self encodeUnindent]; + break; + } + case _C_PTR: + [NSException raise: NSGenericException + format: @"Cannot encode pointers"]; + break; +#if 0 /* No, don't know how far to recurse */ + [self encodeValueOfObjCType:type+1 at:*(char**)d withName:name]; + break; +#endif + default: + [NSException raise: NSGenericException + format: @"type %s not implemented", type]; + } +} + +#define DECODER_FORMAT(TYPE, CONVERSION) \ +@" <%a[^>]> (" ATXSTR(TYPE) @") = %" ATXSTR(CONVERSION) @" \n" + +#define DECODE_ERROR(TYPE) \ +{ \ + id line = [stream readLine]; \ + [NSException raise: NSGenericException \ + format: @"bad format decoding " ATXSTR(TYPE) @".\n" \ + @"Looking at %s\n.", \ + [line cString]]; \ +} + + +#define DECODE_DEBUG(TYPE, CONVERSION) \ +if (debug_textcoder) \ + [[StdioStream standardError] writeFormat: \ + @"got <%s> (%s) %" ATXSTR(CONVERSION) @"\n", \ + tmpname, \ + XSTR(TYPE), *(TYPE*)d]; + +- (void) decodeValueOfCType: (const char*) type + at: (void*) d + withName: (NSString* *) namePtr; +{ + char *tmpname; + + if (!type) + [NSException raise:NSInvalidArgumentException format:@"type is NULL"]; + if (!d) + [NSException raise:NSInvalidArgumentException format:@"d is NULL"]; + + NSAssert(*type != '@', @"tried to decode an \"ObjC\" type"); + NSAssert(*type != '^', @"tried to decode an \"ObjC\" type"); + NSAssert(*type != ':', @"tried to decode an \"ObjC\" type"); + + switch (*type) + { + case _C_LNG: + if ([stream readFormat: DECODER_FORMAT(long,l), + &tmpname, (long*)d] != 2) + DECODE_ERROR(long); + DECODE_DEBUG(long, l); + break; + case _C_ULNG: + if ([stream readFormat:DECODER_FORMAT(unsigned long, lu), + &tmpname, (unsigned long*)d] != 2) + DECODE_ERROR(unsigned long); + DECODE_DEBUG(unsigned long, lu); + break; + case _C_INT: + if ([stream readFormat:DECODER_FORMAT(int, d), + &tmpname, (int*)d] != 2) + DECODE_ERROR(int); + DECODE_DEBUG(int, d); + break; + case _C_UINT: + if ([stream readFormat:DECODER_FORMAT(unsigned int,u), + &tmpname, (unsigned int*)d] != 2) + DECODE_ERROR(unsigned int); + DECODE_DEBUG(unsigned int, u); + break; + case _C_SHT: + if ([stream readFormat:DECODER_FORMAT(short,hd), + &tmpname, (short*)d] != 2) + DECODE_ERROR(short); + DECODE_DEBUG(short, d); + break; + case _C_USHT: + if ([stream readFormat:DECODER_FORMAT(unsigned short,hu), + &tmpname, (unsigned short*)d] != 2) + DECODE_ERROR(unsigned short); + DECODE_DEBUG(unsigned short, u); + break; + case _C_CHR: + { + unsigned tmp; + if ([stream readFormat:@" <%a[^>]> (char) = %*c (%x) \n", + &tmpname, &tmp] != 2) + DECODE_ERROR(char); + *(char*)d = (char)tmp; + DECODE_DEBUG(char, c); + break; + } + case _C_UCHR: + { + unsigned tmp; + if ([stream readFormat:DECODER_FORMAT(unsigned char,x), + &tmpname, &tmp] != 2) + DECODE_ERROR(unsigned char); + *(unsigned char*)d = (unsigned char)tmp; + DECODE_DEBUG(unsigned char, c); + break; + } + case _C_FLT: + if ([stream readFormat:DECODER_FORMAT(float,f), + &tmpname, (float*)d] != 2) + DECODE_ERROR(float); + DECODE_DEBUG(float, f); + break; + case _C_DBL: + if ([stream readFormat:DECODER_FORMAT(double,lf), + &tmpname, (double*)d] != 2) + DECODE_ERROR(double); + DECODE_DEBUG(double, f); + break; + case _C_CHARPTR: + if ([stream readFormat:@" <%a[^>]> (char*) = \"%a[^\"]\" \n", + &tmpname, (char**)d] != 2) + DECODE_ERROR(char*); + DECODE_DEBUG(char*, s); + break; + case _C_ARY_B: + { + /* xxx Do we need to allocate space, just like _C_CHARPTR ? */ + int len = atoi(type+1); + int offset; + [self decodeName:namePtr]; + [self decodeIndent]; + while (isdigit(*++type)); + offset = objc_sizeof_type(type); + while (len-- > 0) + { + [self decodeValueOfCType:type + at:d + withName:namePtr]; + ((char*)d) += offset; + } + [self decodeUnindent]; + break; + } + case _C_STRUCT_B: + { + /* xxx Do we need to allocate space just like char* ? No. */ + int acc_size = 0; + int align; + while (*type != _C_STRUCT_E && *type++ != '='); /* skip "=" */ + [self decodeName:namePtr]; + [self decodeIndent]; /* xxx insert [self decodeName:] */ + while (*type != _C_STRUCT_E) + { + align = objc_alignof_type (type); /* pad to alignment */ + acc_size = ROUND (acc_size, align); + [self decodeValueOfCType:type + at:((char*)d)+acc_size + withName:namePtr]; + acc_size += objc_sizeof_type (type); /* add component size */ + type = objc_skip_typespec (type); /* skip component */ + } + [self decodeUnindent]; + break; + } + case _C_PTR: + [NSException raise: NSGenericException + format: @"Cannot decode pointers"]; + break; +#if 0 /* No, don't know how far to recurse */ + OBJC_MALLOC(*(void**)d, void*, 1); + [self decodeValueOfObjCType:type+1 at:*(char**)d withName:namePtr]; + break; +#endif + default: + [NSException raise: NSGenericException + format: @"type %s not yet implemented", type]; + } + if (namePtr) + *namePtr = [[[NSString alloc] initWithCStringNoCopy: tmpname + length: strlen (tmpname) + freeWhenDone: YES] + autorelease]; + else + objc_free (tmpname); +} + + +/* Encoding/decoding indentation */ + +- (void) encodeIndent +{ + [stream writeFormat: @"%*s {\n", indentation, ""]; + indentation += 2; +} + +- (void) encodeUnindent +{ + indentation -= 2; + [stream writeFormat: @"%*s }\n", indentation, ""]; +} + +- (void) decodeIndent +{ + id line; + const char *lp; + + line = [stream readLine]; + lp = [line cString]; + while (*lp == ' ') lp++; + if (*lp != '{') + [NSException raise: NSGenericException + format: @"bad indent format, got \"%s\"", line]; +} + +- (void) decodeUnindent +{ + id line; + const char *lp; + + line = [stream readLine]; + lp = [line cString]; + while (*lp == ' ') lp++; + if (*lp != '}') + [NSException raise: NSGenericException + format: @"bad unindent format, got \"%s\"", line]; +} + +- (void) encodeName: (NSString*) n +{ + if (n) + [stream writeFormat:@"%*s<%s>\n", indentation, "", [n cString]]; + else + [stream writeFormat:@"%*s\n", indentation, ""]; +} + +- (void) decodeName: (NSString* *) name +{ + char *n; + if (name) + { + if ([stream readFormat: @" <%a[^>]> \n", &n] != 1) + [NSException raise: NSGenericException + format: @"bad format"]; + *name = [[[NSString alloc] initWithCStringNoCopy: n + length: strlen (n) + freeWhenDone: YES] + autorelease]; + if (debug_textcoder) + fprintf(stderr, "got name <%s>\n", n); + } + else + { + [stream readFormat: @" <%*[^>]> \n"]; + } +} + + +/* Returning default format version. */ + ++ (int) defaultFormatVersion +{ + return DEFAULT_FORMAT_VERSION; +} + +@end diff --git a/Old/Time.h b/Old/Time.h new file mode 100644 index 000000000..86d71235a --- /dev/null +++ b/Old/Time.h @@ -0,0 +1,101 @@ +/* Interface for Objective-C Time object + Copyright (C) 1993,1994 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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. +*/ + +/* This is a combination of Smalltalk's Time and Date objects */ + +#ifndef __Time_h_GNUSTEP_BASE_INCLUDE +#define __Time_h_GNUSTEP_BASE_INCLUDE + +#include + +#ifndef __WIN32__ +#include +#include +#endif /* !__WIN32__ */ + +#ifdef _SEQUENT_ +/* Include needed for getclock() in our replacement for gettimeofday() */ +#include + +/* Include needed for tzset() in our replacement for gettimeofday() */ +#include + +/* Sequent does not define struct timezone in any of it's header files */ +struct timezone { + int tz_minuteswest; + int tz_dsttime; +}; +#endif /* _SEQUENT_ */ + +@interface Time : Magnitude +{ + struct timeval tv; /* seconds and useconds */ + struct timezone tz; /* minutes from Greenwich, and correction */ +} + +/* Change these names? */ ++ (long) secondClockValue; ++ getClockValueSeconds: (long *)sec microseconds: (long *)usec; + ++ (long) millisecondsToRun: (void(*)())aFunc; ++ getSeconds: (long *)sec microseconds: (long *)usec toRun: (void(*)())aFunc; + ++ (unsigned) indexOfDayName: (const char *)dayName; ++ (const char *) nameOfDayIndex: (unsigned)dayIndex; ++ (unsigned) indexOfMonthName: (const char *)monthName; ++ (const char *) nameOfMonthIndex: (unsigned)monthIndex; ++ (unsigned) daysInMonthIndex: (unsigned)monthIndex forYear: (unsigned)year; ++ (unsigned) daysInYear: (unsigned)year; ++ (BOOL) leapYear: (unsigned)year; + +- initNow; +- initDayIndex: (unsigned)dayIndex + monthIndex: (unsigned)monthIndex + year: (unsigned)year; +- initSeconds: (long)numSeconds microseconds: (long)numMicroseconds; +- initSeconds: (long)numSeconds; + +- setSeconds: (long)numSeconds microseconds: (long)numMicroseconds; +- setSeconds: (long)numSeconds; + +- (long) days; +- (long) hours; +- (long) minutes; +- (long) seconds; +- (long) microseconds; + +- addTime: (Time*)aTimeObj; +- addDays: (unsigned)num; +- addHours: (unsigned)num; +- addMinutes: (unsigned)num; +- addSeconds: (unsigned)num; + +- subtractTime: (Time*)aTimeObj; +- subtractDays: (unsigned)num; +- subtractHours: (unsigned)num; +- subtractMinutes: (unsigned)num; +- subtractSeconds: (unsigned)num; + +@end + +#endif /* __Time_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/UdpPort.h b/Old/UdpPort.h new file mode 100644 index 000000000..a0386982e --- /dev/null +++ b/Old/UdpPort.h @@ -0,0 +1,62 @@ +/* Interface for socket-based port object for use with Connection + Copyright (C) 1994, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: July 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 __UdpPort_h_GNUSTEP_BASE_INCLUDE +#define __UdpPort_h_GNUSTEP_BASE_INCLUDE + +#include +#include +#ifdef __MINGW32__ +# include +#else +# include +# include +#endif + +@interface UdpInPort : InPort +{ + int _port_socket; + struct sockaddr_in _address; +} + +- (int) portNumber; +- (int) socket; + +@end + +@interface UdpOutPort : OutPort +{ + struct sockaddr_in _address; +} + +- (int) portNumber; +- (NSString*) hostname; + +@end + +@interface UdpInPacket : InPacket +@end +@interface UdpOutPacket : OutPacket +@end + +#endif /* __UdpPort_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/UdpPort.m b/Old/UdpPort.m new file mode 100644 index 000000000..3e03cf7fb --- /dev/null +++ b/Old/UdpPort.m @@ -0,0 +1,479 @@ +/* Implementation of UDP port object for use with Connection + Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Created: July 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. + */ + +/* xxx I should also look into SOCK_RDM and SOCK_SEQPACKET. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#if _AIX +#include +#endif /* _AIX */ + +#ifdef __MINGW__ +#include +#else +#include +#include +#include +#include +#endif /* !__MINGW__ */ + +/* For IRIX machines, which don't define this */ +#ifndef IPPORT_USERRESERVED +#define IPPORT_USERRESERVED 5000 +#endif /* IPPORT_USERRESERVED */ + +@interface UdpInPort (Private) +@end +@interface UdpOutPort (Private) ++ newForSendingToSockaddr: (struct sockaddr_in*)addr; +@end +@interface UdpInPacket (Private) +- (void) _setReplyPort: p; +@end + +/* The maximum size of packet UdpPort's will send or recieve. */ +/* xxx What is the UDP maximum? */ +#define MAX_PACKET_SIZE 2048 + +/* Make this a hashtable? */ +static NSLock* udp_port_gate = nil; + +static BOOL udp_port_debug = NO; + + +/* Our current, sad excuse for a name server. */ + +static unsigned short +name_2_port_number (const char *name) +{ + unsigned int ret = 0; + unsigned int ctr = 0; + + while (*name) + { + ret ^= *name++ << ctr; + ctr = (ctr + 1) % sizeof (void *); + } + return (ret % (65535 - IPPORT_USERRESERVED - 1)) + IPPORT_USERRESERVED; + /* return strlen (name) + IPPORT_USERRESERVED; */ +} + +@implementation UdpInPort + +static NSMapTable *port_number_2_in_port = NULL; + ++ (void) initialize +{ + if (self == [UdpInPort class]) + { + port_number_2_in_port = + NSCreateMapTable (NSIntMapKeyCallBacks, + NSNonOwnedPointerMapValueCallBacks, 0); + } +} + +/* This is the designated initializer. + If N is zero, it will choose a port number for you. */ + ++ newForReceivingFromPortNumber: (unsigned short)n +{ + UdpInPort* p; + + NSAssert(n > IPPORT_USERRESERVED, NSInvalidArgumentException); + + [udp_port_gate lock]; + + /* See if there is already one created */ + if ((p = NSMapGet (port_number_2_in_port, (void*)(int)n))) + return p; + + /* No, create a new port object */ + p = [[self alloc] init]; + + /* Make a new socket for the port object */ + if ((p->_port_socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) + { + perror("[UdpInPort +newForReceivingFromPortNumber:] socket()"); + abort (); + } + + /* Give the socket a name using bind */ + { + struct hostent *hp; + + hp = gethostbyname ([[[NSHost currentHost] name] cString]); + if (!hp) + /* xxx This won't work with port connections on a network, though. + Fix this. Perhaps there is a better way of getting the address + of the local host. */ + hp = gethostbyname ("localhost"); + NSAssert(hp, NSInternalInconsistencyException); + /* Use host's address, and not INADDR_ANY, so that went we + encode our _address for a D.O. operation, they get + our unique host address that can identify us across the network. */ + memcpy (&(p->_address.sin_addr), hp->h_addr, hp->h_length); + p->_address.sin_family = AF_INET; + p->_address.sin_port = NSSwapHostShortToBig (n); + /* N may be zero, in which case bind() will choose a port number + for us. */ + if (bind (p->_port_socket, + (struct sockaddr*) &(p->_address), + sizeof (p->_address)) + < 0) + { + perror ("[UdpInPort +newForReceivingFromPortNumber] bind()"); + abort (); + } + } + + /* If the caller didn't specify a port number, it was chosen for us. + Here, find out what number was chosen. */ + if (!n) + /* xxx Perhaps I should do this unconditionally? */ + { + int size = sizeof (p->_address); + if (getsockname (p->_port_socket, + (struct sockaddr*)&(p->_address), + &size) + < 0) + { + perror ("[UdpInPort +newForReceivingFromPortNumber] getsockname()"); + abort (); + } + NSAssert(p->_address.sin_port, NSInternalInconsistencyException); + } + + /* Record it in UdpInPort's map table. */ + NSMapInsert (port_number_2_in_port, (void*)(int)n, p); + [udp_port_gate unlock]; + + if (udp_port_debug) + fprintf(stderr, "created new UdpInPort 0x%x, fd=%d port_number=%d\n", + (unsigned)p, p->_port_socket, NSSwapHostShortToBig(p->_address.sin_port)); + + return p; +} + ++ newForReceivingFromRegisteredName: (NSString*)name +{ + int n; + + n = name_2_port_number ([name cString]); + return [self newForReceivingFromPortNumber: n]; +} + +/* Returns nil on timeout. + Pass -1 for milliseconds to ignore timeout parameter and block indefinitely. +*/ + +- receivePacketWithTimeout: (int)milliseconds +{ + int r; + struct sockaddr_in remote_addr; + int remote_len; + UdpInPacket *packet; + + if (udp_port_debug) + fprintf(stderr, "receiving from %d\n", [self portNumber]); + + if (milliseconds >= 0) + { + /* A timeout was requested; use select to ask if something is ready. */ + struct timeval timeout; + fd_set ready; + + timeout.tv_sec = milliseconds / 1000; + timeout.tv_usec = (milliseconds % 1000) * 1000; + memset(&ready, '\0', sizeof(ready)); + FD_SET(_port_socket, &ready); + if ((r = select(_port_socket + 1, &ready, 0, 0, &timeout)) < 0) + { + perror("select"); + abort (); + } + + if (r == 0) /* timeout */ + return nil; + if (!FD_ISSET(_port_socket, &ready)) + [self error:"select lied"]; + } + + /* There is a packet on the socket ready for us to receive. */ + + /* Create a packet. */ + packet = [[UdpInPacket alloc] initWithCapacity: MAX_PACKET_SIZE]; + + /* Fill it with the UDP packet data. */ + remote_len = sizeof(remote_addr); + if (recvfrom (_port_socket, [packet streamBuffer], MAX_PACKET_SIZE, 0, + (struct sockaddr*)&remote_addr, &remote_len) + < 0) + { + perror("recvfrom"); + abort (); + } + + /* Set the packet's reply_port. */ + if (remote_len != sizeof(struct sockaddr_in)) + [self error:"remote address size mismatch"]; + [packet _setReplyPort: [[self class] newForSendingToSockaddr: &remote_addr]]; + + return packet; +} + +- (void) invalidate +{ + if (_is_valid) + { +#if defined(__MINGW__) + closesocket (_port_socket); +#else + close (_port_socket); +#endif /* __MINGW__ */ + [super invalidate]; + } +} + +- (void) dealloc +{ + [self invalidate]; + [super dealloc]; +} + +- (int) socket +{ + return _port_socket; +} + +- (int) portNumber +{ + return (int) NSSwapBigShortToHost (_address.sin_port); +} + +- (Class) packetClass +{ + return [UdpInPacket class]; +} + +- (Class) classForPortCoder +{ + /* Make sure that Connection's always send us bycopy, not a Proxy class. + Also, don't encode a "receive right" (ala Mach), encode a "send right". */ + return [UdpOutPort class]; +} +- replacementObjectForPortCoder: aRmc +{ + return self; +} + +- (void) encodeWithCoder: aCoder +{ + /* We are actually encoding a "send right" (ala Mach), + not a receive right. + These values must match those expected by [TcpOutPort +newWithCoder] */ + [super encodeWithCoder: aCoder]; + [aCoder encodeValueOfCType: @encode(typeof(_address.sin_port)) + at: &_address.sin_port + withName: @"socket number"]; + [aCoder encodeValueOfCType: @encode(typeof(_address.sin_addr.s_addr)) + at: &_address.sin_addr.s_addr + withName: @"inet address"]; +} + ++ newWithCoder: aCoder +{ + /* An InPort cannot be created by decoding, only OutPort's. */ + [self shouldNotImplement: _cmd]; + return nil; +} + ++ (void) setDebug: (BOOL)f +{ + udp_port_debug = f; +} + +@end + + + +@implementation UdpOutPort + +static NSMutableArray *udp_out_port_array; + ++ (void) initialize +{ + if (self == [UdpOutPort class]) + { + udp_out_port_array = [NSMutableArray new]; + } +} + +#define SOCKADDR_EQUAL(s1,s2) ((s1)->sin_port == (s2)->sin_port && (s1)->sin_addr.s_addr == (s2)->sin_addr.s_addr) +/* xxx Change to make INADDR_ANY and the localhost address be equal. */ +/* Assume that sin_family is equal */ +/* (!memcmp(s1, s2, sizeof(struct sockaddr_in))) + didn't work because sin_zero's differ. Does this matter? */ + + +/* This is the designated initializer. */ + ++ newForSendingToSockaddr: (struct sockaddr_in*)sockaddr +{ + UdpOutPort *p; + unsigned i; + unsigned c = [udp_out_port_array count]; + + /* See if there already exists a port for this sockaddr; + if so, just return it. */ + for (i = 0; i < c; i++) + { + p = [udp_out_port_array objectAtIndex: i]; + /* xxx Come up with a way to do this with a hashtable, not a list. */ + if (SOCKADDR_EQUAL (sockaddr, &(p->_address))) + return p; + } + + /* Create a new port. */ + p = [[self alloc] init]; + + /* Set the address. */ + memcpy (&(p->_address), sockaddr, sizeof(p->_address)); + + /* Remember it in the array. */ + /* xxx This will retain it; how will it ever get dealloc'ed? */ + [udp_out_port_array addObject: p]; + + return p; +} + + ++ newForSendingToPortNumber: (unsigned short)n + onHost: (NSString*)hostname +{ + struct hostent *hp; + const char *host_cstring; + struct sockaddr_in addr; + + /* Look up the hostname. */ + if (!hostname || ![hostname length]) + host_cstring = "localhost"; + else + host_cstring = [hostname cString]; + hp = gethostbyname ((char*)host_cstring); + if (hp == 0) + [self error: "unknown host: \"%s\"", host_cstring]; + + /* Get the sockaddr_in address. */ + memcpy (&addr.sin_addr, hp->h_addr, hp->h_length); + addr.sin_family = AF_INET; + addr.sin_port = NSSwapHostShortToBig (n); + + return [self newForSendingToSockaddr: &addr]; +} + + +/* This currently ignores the timeout parameter */ + +- (BOOL) sendPacket: packet timeout: (NSTimeInterval)seconds +{ + id reply_port = [packet replyPort]; + int len = [packet streamEofPosition]; + + NSAssert(len < MAX_PACKET_SIZE, NSInternalInconsistencyException); + + if ( ! [reply_port isKindOfClass: [UdpInPort class]]) + [self error:"Trying to send to a port that is not a UdpInPort"]; + if (udp_port_debug) + fprintf (stderr, "sending to %d\n", (int) NSSwapBigShortToHost (_address.sin_port)); + if (sendto ([reply_port socket], + [packet streamBuffer], len, 0, + (struct sockaddr*)&_address, sizeof (_address)) + < 0) + { + perror ("sendto"); + abort (); + } + return YES; +} + +- (int) portNumber +{ + return (int) NSSwapBigShortToHost (_address.sin_port); +} + +- (NSString*) hostname +{ + [self notImplemented: _cmd]; + return nil; +} + +- (Class) packetClass +{ + return [UdpInPacket class]; +} + +- (void) encodeWithCoder: aCoder +{ + [super encodeWithCoder: aCoder]; + [aCoder encodeValueOfCType: @encode(typeof(_address.sin_port)) + at: &_address.sin_port + withName: @"socket number"]; + [aCoder encodeValueOfCType: @encode(typeof(_address.sin_addr.s_addr)) + at: &_address.sin_addr.s_addr + withName: @"inet address"]; +} + ++ newWithCoder: aCoder +{ + struct sockaddr_in addr; + + addr.sin_family = AF_INET; + [aCoder decodeValueOfCType: @encode(typeof(addr.sin_port)) + at: &addr.sin_port + withName: NULL]; + [aCoder decodeValueOfCType: @encode(typeof(addr.sin_addr.s_addr)) + at: &addr.sin_addr.s_addr + withName: NULL]; + return [UdpOutPort newForSendingToSockaddr: &addr]; +} + +@end + + + +@implementation UdpInPacket + +- (void) _setReplyPort: p +{ + [self notImplemented: _cmd]; +} + +@end diff --git a/Old/ValueHolding.h b/Old/ValueHolding.h new file mode 100644 index 000000000..4bd44062b --- /dev/null +++ b/Old/ValueHolding.h @@ -0,0 +1,50 @@ +/* Protocol for Objective-C objects that hold numerical and/or string values. + Copyright (C) 1993,1994 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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 __ValueHolding_h_GNUSTEP_BASE_INCLUDE +#define __ValueHolding_h_GNUSTEP_BASE_INCLUDE + +#include + +/* protocol String; */ + +@protocol ValueGetting +- (int) intValue; +- (float) floatValue; +- (double) doubleValue; +- (const char *) cStringValue; +- /* (NSString*) */ stringValue; +@end + +@protocol ValueSetting +- (void) setIntValue: (int)anInt; +- (void) setFloatValue: (float)aFloat; +- (void) setDoubleValue: (double)aDouble; +- (void) setCStringValue: (const char *)aCString; +- (void) setStringValue: /* (NSString*) */ aString; +@end + +@protocol ValueHolding +@end + +#endif /* __ValueHolding_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/all.h b/Old/all.h new file mode 100644 index 000000000..711ddda15 --- /dev/null +++ b/Old/all.h @@ -0,0 +1,65 @@ +/* Includes interfaces for all concrete objects classes + Copyright (C) 1993,1994, 1996 Free Software Foundation, Inc. + + Written by: Andrew Kachites McCallum + Date: May 1993 + + 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 __o_h_GNUSTEP_BASE_INCLUDE +#define __o_h_GNUSTEP_BASE_INCLUDE + +/* Collection objects */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Stream objects */ +#include +#include +#include + +/* Coder objects */ +#include +#include +#include + +/* Port objects */ +#include + +/* Remote messaging support objects */ +#include + +#include + +#endif /* __o_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/cstream.m b/Old/cstream.m new file mode 100644 index 000000000..9b3a9e69a --- /dev/null +++ b/Old/cstream.m @@ -0,0 +1,57 @@ +/* A demonstration of writing and reading GNU Objective C objects to a file. */ + +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + id arp; + long l = 0x6543; + int i = 0x1234; + unsigned u = 2; + short s = 0x987; + char c = 0x12; + char *string = "Testing"; + float f = 0.1234F; + double d = 0.987654321; + id cstream; + Class cstream_class; + + if (argc > 1) + cstream_class = objc_get_class (argv[1]); + else + cstream_class = [BinaryCStream class]; + + [NSObject enableDoubleReleaseCheck: YES]; + arp = [[NSAutoreleasePool alloc] init]; + + cstream = [[cstream_class alloc] + initForWritingToFile: @"cstream.dat"]; + + /* Write an integer to a file */ + [cstream encodeWithName: @"some values" + valuesOfCTypes: "liIsc*fd", + &l, &i, &u, &s, &c, &string, &f, &d]; + printf ("Wrote %d %d %u %d %d %s %g %.15g\n", + (int)l, i, u, (int)s, (int)c, string, f, d); + [[cstream stream] close]; + + f = d = 0; + + cstream = [cstream_class cStreamReadingFromFile: @"cstream.dat"]; + [cstream decodeWithName: NULL + valuesOfCTypes: "liIsc*fd", + &l, &i, &u, &s, &c, &string, &f, &d]; + printf ("Read %d %d %u %d %d %s %g %.15g\n", + (int)l, i, u, (int)s, (int)c, string, f, d); + [[cstream stream] close]; + + /* Do the autorelease. */ + [arp release]; + + exit(0); +} diff --git a/Old/invocation.m b/Old/invocation.m new file mode 100644 index 000000000..e2fd1e165 --- /dev/null +++ b/Old/invocation.m @@ -0,0 +1,107 @@ +/* A demonstration of writing and reading with NSArchiver */ + +#include +#include +#include +#include +#include +#include + +@interface NSNumber (printing) +- (void) print; +- printAddNumber: n; +@end + +@implementation NSNumber (printing) +- (void) print +{ + printf("%d\n", [self intValue]); +} +- printAddNumber: n +{ + printf("%d\n", [self intValue] + [n intValue]); + return self; +} +@end + +int main() +{ + id obj; + id inv; + id array; + int i; + BOOL b; + NSAutoreleasePool *arp = [NSAutoreleasePool new]; + + /* Create a simple invocation, and get it's return value. */ + obj = [NSObject new]; + inv = [[MethodInvocation alloc] + initWithTarget: obj selector: @selector(isInstance)]; + [inv invoke]; + [inv getReturnValue: &b]; + printf ("object is instance %d\n", (int)b); + [inv release]; + + /* Do a simple invocation on all the contents of a collection. */ + array = [Array new]; + for (i = 0; i < 5; i++) + [array addObject: [NSNumber numberWithInt: i]]; + inv = [[MethodInvocation alloc] + initWithSelector: @selector(print)]; + printf ("The numbers\n"); + [array withObjectsInvoke: inv]; + [inv release]; + + /* Do an invocation on all the contents of the array, but the + array contents become the first object argument of the invocation, + not the target for the invocation. */ + inv = [[ObjectMethodInvocation alloc] + initWithTarget: [NSNumber numberWithInt: 2] + selector: @selector(printAddNumber:), nil]; + printf ("The numbers adding 2\n"); + [array withObjectsInvoke: inv]; + + /* Get an int return value in a way that is simpler than -getReturnValue: */ + printf ("The target number was %d\n", [inv intReturnValue]); + [inv release]; + + /* Use a function instead of a selector for the invocation. + Also show the use of filtered enumerating over a collection. */ + { + id inv2; + id test_func (id o) + { + printf ("test_func got %d\n", [o intValue]); + return [NSNumber numberWithInt: [o intValue] + 3]; + } + inv = [[ObjectFunctionInvocation alloc] + initWithObjectFunction: test_func]; + inv2 = [[MethodInvocation alloc] initWithSelector: @selector(print)]; + [array withObjectsTransformedByInvoking: inv + invoke: inv2]; + [inv release]; + [inv2 release]; + } + + /* Archive the some invocations, read them back and invoke. */ + { + inv = [[MethodInvocation alloc] + initWithTarget: array + selector: @selector(withObjectsInvoke:), + [[[MethodInvocation alloc] initWithSelector: @selector(print)] + autorelease]]; + printf ("Before archiving\n"); + [inv invoke]; + [Archiver setDefaultCStreamClass: [TextCStream class]]; + [Archiver encodeRootObject: inv withName: NULL toFile: @"invocation.txt"]; + [inv release]; + printf ("After archiving\n"); + inv = [Unarchiver decodeObjectWithName: NULL + fromFile: @"invocation.txt"]; + [inv invoke]; + } + + [arp release]; + exit(0); +} + diff --git a/Old/invocation_char.m b/Old/invocation_char.m new file mode 100644 index 000000000..7bf0e6d08 --- /dev/null +++ b/Old/invocation_char.m @@ -0,0 +1,181 @@ +#include +#include +#include +#include +#include + +#define TYPE char + +struct pair { + TYPE i; + TYPE j; +}; + +@interface Pair: NSObject +- (TYPE)member:(Class)c; +- (TYPE)plus: (struct pair) pair; +- (TYPE)plus_ptr: (struct pair*) pair_ptr; +@end + +@implementation Pair +- (TYPE)member:(Class)c +{ + if ([self class] == c) + return YES; + else + return NO; +} +- (TYPE)plus: (struct pair) pair +{ + return (pair.i + pair.j); +} +- (TYPE)plus_ptr: (struct pair*) pair_ptr +{ + return (pair_ptr->i + pair_ptr->j); +} +@end +/* Invocation.m +- initWithTarget: target selector: (SEL)s, ... +[1] Adding CASE_TYPE(_C_CLASS, Class); +[2] Adding default: block + + NSInvocation.h +[3] Adding NS_INVOCATION +[4, 5] Adding NS_MESSAGE + + NSMethodSignature.m +[6] Modifiying -(NSArgumentInfo)argumentInfoAtIndex:(unsigned)index */ + +void test1(); +void test2(); +void test3(); +void test4(); +void test5(); +void test6(); + +int +main () +{ + id pool = [NSAutoreleasePool new]; + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); + [pool release]; +} + +void +test1() +{ + Pair * ipair = [Pair new]; + SEL sel = @selector(member:); + Class c = [Pair class]; + Invocation * inv; + TYPE result; + inv = [[MethodInvocation alloc] + initWithTarget: ipair + selector: sel, c]; + [inv invoke]; + [inv getReturnValue: &result]; + fprintf(stderr, "test1 YES == %s\n", result? "YES": "NO"); +} + +void +test2() +{ + Pair * ipair = [Pair new]; + SEL sel = @selector(plus:); + SEL sel_ptr = @selector(plus_ptr:); + struct pair pair0; + struct pair * pair0_ptr; + Invocation * inv; + TYPE result; + + pair0.i = 3; + pair0.j = 4; + + inv = [[MethodInvocation alloc] + initWithTarget: ipair + selector: sel, pair0]; + [inv invoke]; + [inv getReturnValue: &result]; + fprintf(stderr, "test2-1 %d == 7\n", result); + + pair0_ptr = &pair0; + pair0_ptr->i = 2; + pair0_ptr->j = 3; + inv = [[MethodInvocation alloc] + initWithTarget: ipair + selector: sel_ptr, &pair0]; + [inv invoke]; + [inv getReturnValue: &result]; + fprintf(stderr, "test2-2 %d == 5\n", result); +} + +void +test3() +{ + Pair * ipair = [Pair new]; + struct pair pair0; + NSInvocation * inv; + TYPE x; + pair0.i = 1; + pair0.j = 2; + inv = NS_INVOCATION(Pair , + plus:, + pair0); + [inv setTarget: ipair]; + [inv invoke]; + [inv getReturnValue: &x]; + fprintf(stderr, "test3 3 == %d\n", x); +} + +void +test4() +{ + Pair * ipair = [Pair new]; + struct pair pair0; + NSInvocation * inv; + TYPE x; + pair0.i = 3; + pair0.j = 8; + inv = NS_MESSAGE(ipair , + plus_ptr:, + &pair0); // Method with args + [inv invoke]; + [inv getReturnValue: &x]; + fprintf(stderr, "test4 11 == %d\n", x); +} + +void +test5() +{ + Pair * ipair = [Pair new]; + NSInvocation * inv; + int x; + + inv = NS_MESSAGE(ipair, + hash); // Method with NO args + [inv invoke]; + [inv getReturnValue: &x]; + fprintf(stderr, "test5 hash value of an object == %d\n", x); +} + +void +test6() +{ + NSObject * foo = [NSObject new]; + NSArgumentInfo info; + SEL sel = @selector(isKindOfClass:); + NSMethodSignature * ms = [foo methodSignatureForSelector: sel]; + info = [ms argumentInfoAtIndex: 0]; + fprintf(stderr, "test6 (%d, %d, %s)\n", info.offset, info.size, info.type); + info = [ms argumentInfoAtIndex: 1]; + fprintf(stderr, "test6 (%d, %d, %s)\n", info.offset, info.size, info.type); + info = [ms argumentInfoAtIndex: 2]; + fprintf(stderr, "test6 (%d, %d, %s)\n", info.offset, info.size, info.type); +} + +#undef TYPE diff --git a/Old/invocation_int.m b/Old/invocation_int.m new file mode 100644 index 000000000..2f761b3d3 --- /dev/null +++ b/Old/invocation_int.m @@ -0,0 +1,181 @@ +#include +#include +#include +#include +#include + +#define TYPE int + +struct pair { + TYPE i; + TYPE j; +}; + +@interface Pair: NSObject +- (TYPE)member:(Class)c; +- (TYPE)plus: (struct pair) pair; +- (TYPE)plus_ptr: (struct pair*) pair_ptr; +@end + +@implementation Pair +- (TYPE)member:(Class)c +{ + if ([self class] == c) + return YES; + else + return NO; +} +- (TYPE)plus: (struct pair) pair +{ + return (pair.i + pair.j); +} +- (TYPE)plus_ptr: (struct pair*) pair_ptr +{ + return (pair_ptr->i + pair_ptr->j); +} +@end +/* Invocation.m +- initWithTarget: target selector: (SEL)s, ... +[1] Adding CASE_TYPE(_C_CLASS, Class); +[2] Adding default: block + + NSInvocation.h +[3] Adding NS_INVOCATION +[4, 5] Adding NS_MESSAGE + + NSMethodSignature.m +[6] Modifiying -(NSArgumentInfo)argumentInfoAtIndex:(unsigned)index */ + +void test1(); +void test2(); +void test3(); +void test4(); +void test5(); +void test6(); + +int +main () +{ + id pool = [NSAutoreleasePool new]; + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); + [pool release]; +} + +void +test1() +{ + Pair * ipair = [Pair new]; + SEL sel = @selector(member:); + Class c = [Pair class]; + Invocation * inv; + TYPE result; + inv = [[MethodInvocation alloc] + initWithTarget: ipair + selector: sel, c]; + [inv invoke]; + [inv getReturnValue: &result]; + fprintf(stderr, "test1 YES == %s\n", result? "YES": "NO"); +} + +void +test2() +{ + Pair * ipair = [Pair new]; + SEL sel = @selector(plus:); + SEL sel_ptr = @selector(plus_ptr:); + struct pair pair0; + struct pair * pair0_ptr; + Invocation * inv; + TYPE result; + + pair0.i = 3; + pair0.j = 4; + + inv = [[MethodInvocation alloc] + initWithTarget: ipair + selector: sel, pair0]; + [inv invoke]; + [inv getReturnValue: &result]; + fprintf(stderr, "test2-1 %d == 7\n", result); + + pair0_ptr = &pair0; + pair0_ptr->i = 2; + pair0_ptr->j = 3; + inv = [[MethodInvocation alloc] + initWithTarget: ipair + selector: sel_ptr, &pair0]; + [inv invoke]; + [inv getReturnValue: &result]; + fprintf(stderr, "test2-2 %d == 5\n", result); +} + +void +test3() +{ + Pair * ipair = [Pair new]; + struct pair pair0; + NSInvocation * inv; + TYPE x; + pair0.i = 1; + pair0.j = 2; + inv = NS_INVOCATION(Pair , + plus:, + pair0); + [inv setTarget: ipair]; + [inv invoke]; + [inv getReturnValue: &x]; + fprintf(stderr, "test3 3 == %d\n", x); +} + +void +test4() +{ + Pair * ipair = [Pair new]; + struct pair pair0; + NSInvocation * inv; + TYPE x; + pair0.i = 3; + pair0.j = 8; + inv = NS_MESSAGE(ipair , + plus_ptr:, + &pair0); // Method with args + [inv invoke]; + [inv getReturnValue: &x]; + fprintf(stderr, "test4 11 == %d\n", x); +} + +void +test5() +{ + Pair * ipair = [Pair new]; + NSInvocation * inv; + int x; + + inv = NS_MESSAGE(ipair, + hash); // Method with NO args + [inv invoke]; + [inv getReturnValue: &x]; + fprintf(stderr, "test5 hash value of an object == %d\n", x); +} + +void +test6() +{ + NSObject * foo = [NSObject new]; + NSArgumentInfo info; + SEL sel = @selector(isKindOfClass:); + NSMethodSignature * ms = [foo methodSignatureForSelector: sel]; + info = [ms argumentInfoAtIndex: 0]; + fprintf(stderr, "test6 (%d, %d, %s)\n", info.offset, info.size, info.type); + info = [ms argumentInfoAtIndex: 1]; + fprintf(stderr, "test6 (%d, %d, %s)\n", info.offset, info.size, info.type); + info = [ms argumentInfoAtIndex: 2]; + fprintf(stderr, "test6 (%d, %d, %s)\n", info.offset, info.size, info.type); +} + +#undef TYPE diff --git a/Old/invocation_long.m b/Old/invocation_long.m new file mode 100644 index 000000000..c7a420b1e --- /dev/null +++ b/Old/invocation_long.m @@ -0,0 +1,181 @@ +#include +#include +#include +#include +#include + +#define TYPE long + +struct pair { + TYPE i; + TYPE j; +}; + +@interface Pair: NSObject +- (TYPE)member:(Class)c; +- (TYPE)plus: (struct pair) pair; +- (TYPE)plus_ptr: (struct pair*) pair_ptr; +@end + +@implementation Pair +- (TYPE)member:(Class)c +{ + if ([self class] == c) + return YES; + else + return NO; +} +- (TYPE)plus: (struct pair) pair +{ + return (pair.i + pair.j); +} +- (TYPE)plus_ptr: (struct pair*) pair_ptr +{ + return (pair_ptr->i + pair_ptr->j); +} +@end +/* Invocation.m +- initWithTarget: target selector: (SEL)s, ... +[1] Adding CASE_TYPE(_C_CLASS, Class); +[2] Adding default: block + + NSInvocation.h +[3] Adding NS_INVOCATION +[4, 5] Adding NS_MESSAGE + + NSMethodSignature.m +[6] Modifiying -(NSArgumentInfo)argumentInfoAtIndex:(unsigned)index */ + +void test1(); +void test2(); +void test3(); +void test4(); +void test5(); +void test6(); + +int +main () +{ + id pool = [NSAutoreleasePool new]; + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); + [pool release]; +} + +void +test1() +{ + Pair * ipair = [Pair new]; + SEL sel = @selector(member:); + Class c = [Pair class]; + Invocation * inv; + TYPE result; + inv = [[MethodInvocation alloc] + initWithTarget: ipair + selector: sel, c]; + [inv invoke]; + [inv getReturnValue: &result]; + fprintf(stderr, "test1 YES == %s\n", result? "YES": "NO"); +} + +void +test2() +{ + Pair * ipair = [Pair new]; + SEL sel = @selector(plus:); + SEL sel_ptr = @selector(plus_ptr:); + struct pair pair0; + struct pair * pair0_ptr; + Invocation * inv; + TYPE result; + + pair0.i = 3; + pair0.j = 4; + + inv = [[MethodInvocation alloc] + initWithTarget: ipair + selector: sel, pair0]; + [inv invoke]; + [inv getReturnValue: &result]; + fprintf(stderr, "test2-1 %d == 7\n", result); + + pair0_ptr = &pair0; + pair0_ptr->i = 2; + pair0_ptr->j = 3; + inv = [[MethodInvocation alloc] + initWithTarget: ipair + selector: sel_ptr, &pair0]; + [inv invoke]; + [inv getReturnValue: &result]; + fprintf(stderr, "test2-2 %d == 5\n", result); +} + +void +test3() +{ + Pair * ipair = [Pair new]; + struct pair pair0; + NSInvocation * inv; + TYPE x; + pair0.i = 1; + pair0.j = 2; + inv = NS_INVOCATION(Pair , + plus:, + pair0); + [inv setTarget: ipair]; + [inv invoke]; + [inv getReturnValue: &x]; + fprintf(stderr, "test3 3 == %d\n", x); +} + +void +test4() +{ + Pair * ipair = [Pair new]; + struct pair pair0; + NSInvocation * inv; + TYPE x; + pair0.i = 3; + pair0.j = 8; + inv = NS_MESSAGE(ipair , + plus_ptr:, + &pair0); // Method with args + [inv invoke]; + [inv getReturnValue: &x]; + fprintf(stderr, "test4 11 == %d\n", x); +} + +void +test5() +{ + Pair * ipair = [Pair new]; + NSInvocation * inv; + int x; + + inv = NS_MESSAGE(ipair, + hash); // Method with NO args + [inv invoke]; + [inv getReturnValue: &x]; + fprintf(stderr, "test5 hash value of an object == %d\n", x); +} + +void +test6() +{ + NSObject * foo = [NSObject new]; + NSArgumentInfo info; + SEL sel = @selector(isKindOfClass:); + NSMethodSignature * ms = [foo methodSignatureForSelector: sel]; + info = [ms argumentInfoAtIndex: 0]; + fprintf(stderr, "test6 (%d, %d, %s)\n", info.offset, info.size, info.type); + info = [ms argumentInfoAtIndex: 1]; + fprintf(stderr, "test6 (%d, %d, %s)\n", info.offset, info.size, info.type); + info = [ms argumentInfoAtIndex: 2]; + fprintf(stderr, "test6 (%d, %d, %s)\n", info.offset, info.size, info.type); +} + +#undef TYPE diff --git a/Old/invocation_short.m b/Old/invocation_short.m new file mode 100644 index 000000000..da1a89d94 --- /dev/null +++ b/Old/invocation_short.m @@ -0,0 +1,179 @@ +#include +#include +#include +#include +#include + +#define TYPE short + +struct pair { + TYPE i; + TYPE j; +}; + +@interface Pair: NSObject +- (TYPE)member:(Class)c; +- (TYPE)plus: (struct pair) pair; +- (TYPE)plus_ptr: (struct pair*) pair_ptr; +@end + +@implementation Pair +- (TYPE)member:(Class)c +{ + if ([self class] == c) + return YES; + else + return NO; +} +- (TYPE)plus: (struct pair) pair +{ + return (pair.i + pair.j); +} +- (TYPE)plus_ptr: (struct pair*) pair_ptr +{ + return (pair_ptr->i + pair_ptr->j); +} +@end +/* Invocation.m +- initWithTarget: target selector: (SEL)s, ... +[1] Adding CASE_TYPE(_C_CLASS, Class); +[2] Adding default: block + + NSInvocation.h +[3] Adding NS_INVOCATION +[4, 5] Adding NS_MESSAGE + + NSMethodSignature.m +[6] Modifiying -(NSArgumentInfo)argumentInfoAtIndex:(unsigned)index */ + +void test1(); +void test2(); +void test3(); +void test4(); +void test5(); +void test6(); + +int +main () +{ + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); +} + +void +test1() +{ + Pair * ipair = [Pair new]; + SEL sel = @selector(member:); + Class c = [Pair class]; + Invocation * inv; + TYPE result; + inv = [[MethodInvocation alloc] + initWithTarget: ipair + selector: sel, c]; + [inv invoke]; + [inv getReturnValue: &result]; + fprintf(stderr, "test1 YES == %s\n", result? "YES": "NO"); +} + +void +test2() +{ + Pair * ipair = [Pair new]; + SEL sel = @selector(plus:); + SEL sel_ptr = @selector(plus_ptr:); + struct pair pair0; + struct pair * pair0_ptr; + Invocation * inv; + TYPE result; + + pair0.i = 3; + pair0.j = 4; + + inv = [[MethodInvocation alloc] + initWithTarget: ipair + selector: sel, pair0]; + [inv invoke]; + [inv getReturnValue: &result]; + fprintf(stderr, "test2-1 %d == 7\n", result); + + pair0_ptr = &pair0; + pair0_ptr->i = 2; + pair0_ptr->j = 3; + inv = [[MethodInvocation alloc] + initWithTarget: ipair + selector: sel_ptr, &pair0]; + [inv invoke]; + [inv getReturnValue: &result]; + fprintf(stderr, "test2-2 %d == 5\n", result); +} + +void +test3() +{ + Pair * ipair = [Pair new]; + struct pair pair0; + NSInvocation * inv; + TYPE x; + pair0.i = 1; + pair0.j = 2; + inv = NS_INVOCATION(Pair , + plus:, + pair0); + [inv setTarget: ipair]; + [inv invoke]; + [inv getReturnValue: &x]; + fprintf(stderr, "test3 3 == %d\n", x); +} + +void +test4() +{ + Pair * ipair = [Pair new]; + struct pair pair0; + NSInvocation * inv; + TYPE x; + pair0.i = 3; + pair0.j = 8; + inv = NS_MESSAGE(ipair , + plus_ptr:, + &pair0); // Method with args + [inv invoke]; + [inv getReturnValue: &x]; + fprintf(stderr, "test4 11 == %d\n", x); +} + +void +test5() +{ + Pair * ipair = [Pair new]; + NSInvocation * inv; + int x; + + inv = NS_MESSAGE(ipair, + hash); // Method with NO args + [inv invoke]; + [inv getReturnValue: &x]; + fprintf(stderr, "test5 hash value of an object == %d\n", x); +} + +void +test6() +{ + NSObject * foo = [NSObject new]; + NSArgumentInfo info; + SEL sel = @selector(isKindOfClass:); + NSMethodSignature * ms = [foo methodSignatureForSelector: sel]; + info = [ms argumentInfoAtIndex: 0]; + fprintf(stderr, "test6 (%d, %d, %s)\n", info.offset, info.size, info.type); + info = [ms argumentInfoAtIndex: 1]; + fprintf(stderr, "test6 (%d, %d, %s)\n", info.offset, info.size, info.type); + info = [ms argumentInfoAtIndex: 2]; + fprintf(stderr, "test6 (%d, %d, %s)\n", info.offset, info.size, info.type); +} + +#undef TYPE diff --git a/Old/ostream.h b/Old/ostream.h new file mode 100644 index 000000000..075e05a7d --- /dev/null +++ b/Old/ostream.h @@ -0,0 +1,84 @@ +/* ostream.h - C-function interface to GNUstep Objective-C streams + Copyright (C) 1996 Free Software Foundation, Inc. + + Written by: Adam Fedor + Date: Jun 1996 + + 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 __objc_stream_h_GNUSTEP_BASE_INCLUDE +#define __objc_stream_h_GNUSTEP_BASE_INCLUDE + +#include +#include +#include + +typedef struct _ostream +{ + void* stream_obj; + int flags; +} ostream; + +/* Access modes */ +#define OSTREAM_READONLY 1 /* read on stream only */ +#define OSTREAM_WRITEONLY 2 /* write on stream only */ +#define OSTREAM_READWRITE 4 /* do read & write */ +#define OSTREAM_APPEND 8 /* append (write at end of file) */ + +/* Seek modes */ +#define OSTREAM_SEEK_FROM_START 0 +#define OSTREAM_SEEK_FROM_CURRENT 1 +#define OSTREAM_SEEK_FROM_END 2 + +/* Private flags */ +#define OSTREAM_READFLAG 1 /* stream is for reading */ +#define OSTREAM_WRITEFLAG (1 << 1) /* stream is for writing */ +#define OSTREAM_ISBUFFER (1 << 2) +#define OSTREAM_USER_OWNS_BUF (1 << 3) +#define OSTREAM_CANSEEK (1 << 4) + +GS_EXPORT int ostream_getc (ostream* s); +GS_EXPORT void ostream_ungetc (ostream* s); +GS_EXPORT int ostream_putc (ostream* s, int c); +GS_EXPORT BOOL ostream_at_eos (ostream* s); +GS_EXPORT char* ostream_gets (ostream* s, char* buf, int count); + +GS_EXPORT int ostream_flush (ostream *s); +GS_EXPORT void ostream_seek (ostream *s, long offset, int mode); +GS_EXPORT long ostream_tell (ostream *s); +GS_EXPORT int ostream_read (ostream* s, void* buf, int count); +GS_EXPORT int ostream_write (ostream* s, const void* buf, int count); +GS_EXPORT void ostream_printf (ostream *s, const char *format, ...); +GS_EXPORT void ostream_vprintf (ostream *s, const char *format, va_list argList); +GS_EXPORT int ostream_scanf (ostream *s, const char *format, ...); +GS_EXPORT int ostream_vscanf (ostream *s, const char *format, va_list argList); + +GS_EXPORT ostream *ostream_open_descriptor (int fd, int mode); +GS_EXPORT ostream *ostream_open_memory (const char *addr, int size, int mode); +GS_EXPORT ostream *ostream_map_file (const char *name, int mode); +GS_EXPORT int ostream_save_to_file (ostream *s, const char *name); +GS_EXPORT void ostream_get_memory_buffer (ostream *s, char **addr, + int *len, int *maxlen); +GS_EXPORT void ostream_close_memory (ostream *s, int option); +GS_EXPORT void ostream_close (ostream *s); + +#define OSTREAM_FREEBUFFER 0 +#define OSTREAM_TRUNCATEBUFFER 1 +#define OSTREAM_SAVEBUFFER 2 + +#endif /* __objc_stream_h_GNUSTEP_BASE_INCLUDE */ diff --git a/Old/ostream.m b/Old/ostream.m new file mode 100644 index 000000000..f25b833d2 --- /dev/null +++ b/Old/ostream.m @@ -0,0 +1,366 @@ +/* objc_streams - C-function interface to Objective-C streams + Copyright (C) 1996 Free Software Foundation, Inc. + + Written by: Adam Fedor + Date: Aug 1996 + + 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. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define OSTREAM_EOF EOF + +/* Handle a stream error - FIXME: not sure if this should throw an exception + or what... */ +static void +_ostream_error (const char* message) +{ + fprintf (stderr, "ostream error: %s\n", message); +} + +int +ostream_getc (ostream* s) +{ + char r, c; + r = c = 0; + if (s->flags & OSTREAM_READFLAG) + r = [(id )s->stream_obj readByte: &c]; + if (r == 0) + c = OSTREAM_EOF; + return c; +} + +void +ostream_ungetc (ostream* s) +{ + if ((s->flags & OSTREAM_READFLAG) && (s->flags & OSTREAM_CANSEEK)) + { + long pos = [(id )s->stream_obj streamPosition]; + [(id )s->stream_obj setStreamPosition: pos-1]; + } + else + _ostream_error("Tried to unget on non-readable/non-seekable stream"); +} + +int +ostream_putc (ostream* s, int c) +{ + if (s->flags & OSTREAM_WRITEFLAG) + return [(id )s->stream_obj writeByte: c]; + else + return OSTREAM_EOF; +} + +BOOL +ostream_at_eos (ostream* s) +{ + return [(id )s->stream_obj isAtEof]; +} + + +int +ostream_flush (ostream *s) +{ + int pos; + pos = [(id )s->stream_obj streamPosition]; + [(id )s->stream_obj flushStream]; + return [(id )s->stream_obj streamPosition] - pos; +} + +void +ostream_seek (ostream *s, long offset, int mode) +{ + if (!(s->flags & OSTREAM_CANSEEK)) + return; + + [(id )s->stream_obj setStreamPosition: offset + seekMode: (mode - OSTREAM_SEEK_FROM_START + STREAM_SEEK_FROM_START)]; +} + +long +ostream_tell (ostream *s) +{ + return [(id )s->stream_obj streamPosition]; +} + +int +ostream_read (ostream* s, void* buf, int count) +{ + int r = 0; + + if (!buf) + [NSException raise:NSInvalidArgumentException format:@"buf is NULL"]; + + if (s->flags & OSTREAM_READFLAG) + r = [(id )s->stream_obj readBytes: buf length: count]; + if (r == 0) + r = OSTREAM_EOF; + return r; +} + +char* ostream_gets (ostream* s, char* buf, int count) +{ + char r, c; + int i = 0; + + if (!buf) + [NSException raise:NSInvalidArgumentException format:@"buf is NULL"]; + + if (!(s->flags & OSTREAM_READFLAG)) + return NULL; + while (i < count-1) { + r = [(id )s->stream_obj readByte: &c]; + if (r <= 0) + break; + buf[i++] = c; + if (c == '\n') + break; + } + buf[i++] = 0; + + return i > 1 ? buf : NULL; +} + +int +ostream_write (ostream* s, const void* buf, int count) +{ + if (!buf) + [NSException raise:NSInvalidArgumentException format:@"buf is NULL"]; + + if (s->flags & OSTREAM_WRITEFLAG) + return [(id )s->stream_obj writeBytes: buf length: count]; + return OSTREAM_EOF; +} + +void +ostream_printf (ostream *s, const char *format, ...) +{ + va_list args; + va_start(args, format); + ostream_vprintf(s, format, args); + va_end(args); +} + +void +ostream_vprintf (ostream *s, const char *format, va_list argList) +{ + id str = [[NSString alloc] initWithCString: format]; + if (s->flags & OSTREAM_WRITEFLAG) + [(id )s->stream_obj writeFormat: str arguments: argList]; + else + _ostream_error("Tried to write to non-writable stream"); + [str release]; +} + +int +ostream_scanf (ostream *s, const char *format, ...) +{ + int ret; + va_list args; + va_start(args, format); + ret = ostream_vscanf(s, format, args); + va_end(args); + return ret; +} + +int +ostream_vscanf (ostream *s, const char *format, va_list argList) +{ + id str = [[NSString alloc] stringWithCString: format]; + if (s->flags & OSTREAM_READFLAG) + { + int r = 0; + r = [(id )s->stream_obj readFormat: str + arguments: argList]; + if (r == 0) + r = OSTREAM_EOF; + return r; + } + _ostream_error("Tried to read from non-readable stream"); + [str release]; + return OSTREAM_EOF; +} + +static ostream * +_ostream_new_stream_struct (int mode, char** cmode) +{ + char* fmode; + ostream* stream; + OBJC_MALLOC(stream, ostream, 1); + stream->flags = 0; + switch (mode) + { + case OSTREAM_READONLY: + fmode = "r"; + stream->flags |= OSTREAM_READFLAG; + break; + case OSTREAM_WRITEONLY: + fmode = "w"; + stream->flags |= OSTREAM_WRITEFLAG; + break; + case OSTREAM_READWRITE: + fmode = "r+"; + stream->flags |= OSTREAM_READFLAG; + stream->flags |= OSTREAM_WRITEFLAG; + break; + case OSTREAM_APPEND: + fmode = "r+"; + stream->flags |= OSTREAM_WRITEFLAG; + break; + default: + fmode = "r"; + break; + } + if (cmode) + *cmode = fmode; + return stream; +} + +ostream * +ostream_open_descriptor (int fd, int mode) +{ + char* fmode; + ostream* stream = _ostream_new_stream_struct(mode, &fmode); + stream->stream_obj = [[StdioStream alloc] initWithFileDescriptor: fd + fmode: fmode]; + /* FIXME: Just assuming we can seek FILE streams */ + stream->flags |= OSTREAM_CANSEEK; + return stream; +} + +ostream * +ostream_open_memory (const char *addr, int size, int mode) +{ + char* fmode; + ostream* stream = _ostream_new_stream_struct(mode, &fmode); + if (addr) + { + stream->stream_obj = [[MemoryStream alloc] + _initOnMallocBuffer: (char*)addr + freeWhenDone: NO + size: size + eofPosition: size + prefix: 0 + position: 0]; + if (!stream->stream_obj) + return NULL; + } + else + { + stream->stream_obj = [[MemoryStream alloc] initWithCapacity: size + prefix: 0]; + } + if (mode == OSTREAM_APPEND) + ostream_seek(stream, 0, OSTREAM_SEEK_FROM_END); + stream->flags |= OSTREAM_CANSEEK; + stream->flags |= OSTREAM_ISBUFFER; + return stream; +} + +ostream * +ostream_map_file (const char *name, int mode) +{ + char* fmode; + NSString* str = [NSString stringWithCString: name]; + ostream* stream = _ostream_new_stream_struct(mode, &fmode); + stream->stream_obj = [[StdioStream alloc] initWithFilename: str + fmode: fmode]; + if (!stream->stream_obj) + return NULL; + + /* xxxFIXME: Just assuming that we can seek: */ + stream->flags |= OSTREAM_CANSEEK; + if (mode == OSTREAM_APPEND) + ostream_seek(stream, 0, OSTREAM_SEEK_FROM_END); + return stream; +} + +/* Would like to use NSData for this, but it's to hard to pass the buffer + and tell NSData not to free it */ +int +ostream_save_to_file (ostream *s, const char *name) +{ + StdioStream* output; + if (!(s->flags & OSTREAM_ISBUFFER)) + { + _ostream_error("Tried to save non-memory stream"); + return -1; + } + + output = [[StdioStream alloc] + initWithFilename: [NSString stringWithCString: name] + fmode: "w"]; + if (!output) + { + _ostream_error("Unable to open save file"); + return -1; + } + + [output writeBytes: [(id )s->stream_obj streamBuffer] + length: [(id )s->stream_obj streamEofPosition]]; + [output release]; + return 0; +} + +void +ostream_get_memory_buffer (ostream *s, char **addr, int *len, int *maxlen) +{ + if (!(s->flags & OSTREAM_ISBUFFER)) + { + if (addr) + *addr = 0; + return; + } + + if (addr) + *addr = [(id )s->stream_obj streamBuffer]; + if (len) + *len = [(id )s->stream_obj streamEofPosition]; + if (maxlen) + *maxlen = [(id )s->stream_obj streamBufferCapacity]; +} + +void +ostream_close_memory (ostream *s, int option) +{ + if (s->flags & OSTREAM_ISBUFFER) + { + /* Dumb way to save buffer, but what else? */ + if (option == OSTREAM_SAVEBUFFER) + [(MemoryStream*)s->stream_obj retain]; + } + ostream_close(s); +} + +void +ostream_close (ostream *s) +{ + [(id )s->stream_obj close]; + [(id)s->stream_obj release]; + s->stream_obj = 0; + OBJC_FREE(s); +} + + diff --git a/Old/pipes.m b/Old/pipes.m new file mode 100644 index 000000000..473637afb --- /dev/null +++ b/Old/pipes.m @@ -0,0 +1,17 @@ +#include +#include + +int main() +{ + char b[100]; + int len; + id s = [[StdioStream alloc] initWithPipeFrom: @"cat /etc/group | sort"]; + + while ((len = [s readBytes:b length:99]) > 0) + { + b[len] = '\0'; + printf("[%d]: %s\n", len, b); + } + + exit(0); +}