aboutsummaryrefslogtreecommitdiff
path: root/gnu/usr.bin/cc/libobjc
diff options
context:
space:
mode:
authorsvn2git <svn2git@FreeBSD.org>1994-05-01 08:00:00 +0000
committersvn2git <svn2git@FreeBSD.org>1994-05-01 08:00:00 +0000
commita16f65c7d117419bd266c28a1901ef129a337569 (patch)
tree2626602f66dc3551e7a7c7bc9ad763c3bc7ab40a /gnu/usr.bin/cc/libobjc
parent8503f4f13f77abf7adc8f7e329c6f9c1d52b6a20 (diff)
This commit was manufactured to restore the state of the 1.1-RELEASE image. Releases prior to 5.3-RELEASE are omitting the secure/ and crypto/ subdirs.
Diffstat (limited to 'gnu/usr.bin/cc/libobjc')
-rw-r--r--gnu/usr.bin/cc/libobjc/Makefile31
-rw-r--r--gnu/usr.bin/cc/libobjc/Object.h121
-rw-r--r--gnu/usr.bin/cc/libobjc/Object.m358
-rw-r--r--gnu/usr.bin/cc/libobjc/Protocol.h57
-rw-r--r--gnu/usr.bin/cc/libobjc/Protocol.m127
-rw-r--r--gnu/usr.bin/cc/libobjc/archive.c1492
-rw-r--r--gnu/usr.bin/cc/libobjc/class.c350
-rw-r--r--gnu/usr.bin/cc/libobjc/gstdarg.h156
-rw-r--r--gnu/usr.bin/cc/libobjc/hash.c250
-rw-r--r--gnu/usr.bin/cc/libobjc/hash.h200
-rw-r--r--gnu/usr.bin/cc/libobjc/init.c275
-rw-r--r--gnu/usr.bin/cc/libobjc/list.h145
-rw-r--r--gnu/usr.bin/cc/libobjc/misc.c72
-rw-r--r--gnu/usr.bin/cc/libobjc/objc-api.h450
-rw-r--r--gnu/usr.bin/cc/libobjc/objc.h185
-rw-r--r--gnu/usr.bin/cc/libobjc/objects.c91
-rw-r--r--gnu/usr.bin/cc/libobjc/runtime.h73
-rw-r--r--gnu/usr.bin/cc/libobjc/sarray.c435
-rw-r--r--gnu/usr.bin/cc/libobjc/sarray.h235
-rw-r--r--gnu/usr.bin/cc/libobjc/selector.c139
-rw-r--r--gnu/usr.bin/cc/libobjc/sendmsg.c471
-rw-r--r--gnu/usr.bin/cc/libobjc/typedstream.h132
22 files changed, 5845 insertions, 0 deletions
diff --git a/gnu/usr.bin/cc/libobjc/Makefile b/gnu/usr.bin/cc/libobjc/Makefile
new file mode 100644
index 000000000000..a5903126bdca
--- /dev/null
+++ b/gnu/usr.bin/cc/libobjc/Makefile
@@ -0,0 +1,31 @@
+LIB= objc
+CC= gcc
+
+NOPROFILE=no
+
+CFLAGS+= -I${.CURDIR} -I${.CURDIR}/.. -I${.CURDIR}/../lib
+
+SRCS = hash.c sarray.c class.c sendmsg.c init.c archive.c \
+ selector.c objects.c misc.c Object.m Protocol.m
+
+OBJC_HDRS = hash.h list.h sarray.h objc.h \
+ objc-api.h \
+ Object.h Protocol.h \
+ typedstream.h
+
+OBJC_HDR_DESTDIR = ${DESTDIR}/usr/include/objc
+
+beforeinstall:
+ @-if [ ! -d ${OBJC_HDR_DESTDIR} ]; then \
+ mkdir ${OBJC_HDR_DESTDIR}; \
+ chown ${BINOWN}.${BINGRP} ${OBJC_HDR_DESTDIR}; \
+ chmod 755 ${OBJC_HDR_DESTDIR}; \
+ fi
+ @echo installing includes into objc
+ @-for file in ${OBJC_HDRS}; do \
+ cmp -s ${.CURDIR}/$$file ${OBJC_HDR_DESTDIR}/$$file || \
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/$$file \
+ ${OBJC_HDR_DESTDIR}/$$file; \
+ done
+
+.include <bsd.lib.mk>
diff --git a/gnu/usr.bin/cc/libobjc/Object.h b/gnu/usr.bin/cc/libobjc/Object.h
new file mode 100644
index 000000000000..917fed55a877
--- /dev/null
+++ b/gnu/usr.bin/cc/libobjc/Object.h
@@ -0,0 +1,121 @@
+/* Interface for the Object class for Objective-C.
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU CC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* As a special exception, if you link this library with files compiled
+ with GCC to produce an executable, this does not cause the resulting
+ executable to be covered by the GNU General Public License. This
+ exception does not however invalidate any other reasons why the
+ executable file might be covered by the GNU General Public License. */
+
+#ifndef __object_INCLUDE_GNU
+#define __object_INCLUDE_GNU
+
+#include <objc/objc.h>
+#include <objc/typedstream.h>
+
+/*
+ * All classes are derived from Object. As such,
+ * this is the overhead tacked onto those objects.
+ */
+@interface Object
+{
+ Class* isa; /* A pointer to the instance's class structure */
+}
+
+ /* Initializing classes and instances */
++ initialize;
+- init;
+
+ /* Creating, freeing, and copying instances */
++ new;
++ alloc;
+- free;
+- copy;
+- shallowCopy;
+- deepen;
+- deepCopy;
+
+ /* Identifying classes */
+- (Class*)class;
+- (Class*)superClass;
+- (MetaClass*)metaClass;
+- (const char *)name;
+
+ /* Identifying and comparing objects */
+- self;
+- (unsigned int)hash;
+- (BOOL)isEqual:anObject;
+
+ /* Testing object type */
+- (BOOL)isMetaClass;
+- (BOOL)isClass;
+- (BOOL)isInstance;
+
+ /* Testing inheritance relationships */
+- (BOOL)isKindOf:(Class*)aClassObject;
+- (BOOL)isMemberOf:(Class*)aClassObject;
+- (BOOL)isKindOfClassNamed:(const char *)aClassName;
+- (BOOL)isMemberOfClassNamed:(const char *)aClassName;
+
+ /* Testing class functionality */
++ (BOOL)instancesRespondTo:(SEL)aSel;
+- (BOOL)respondsTo:(SEL)aSel;
+
+ /* Testing protocol conformance */
+- (BOOL)conformsTo:(Protocol*)aProtocol;
+
+ /* Introspection */
++ (IMP)instanceMethodFor:(SEL)aSel;
+- (IMP)methodFor:(SEL)aSel;
++ (struct objc_method_description *)descriptionForInstanceMethod:(SEL)aSel;
+- (struct objc_method_description *)descriptionForMethod:(SEL)aSel;
+
+ /* Sending messages determined at run time */
+- perform:(SEL)aSel;
+- perform:(SEL)aSel with:anObject;
+- perform:(SEL)aSel with:anObject1 with:anObject2;
+
+ /* Forwarding */
+- forward:(SEL)aSel :(arglist_t)argFrame;
+- performv:(SEL)aSel :(arglist_t)argFrame;
+
+ /* Posing */
++ poseAs:(Class*)aClassObject;
+- (Class*)transmuteClassTo:(Class*)aClassObject;
+
+ /* Enforcing intentions */
+- subclassResponsibility:(SEL)aSel;
+- notImplemented:(SEL)aSel;
+
+ /* Error handling */
+- doesNotRecognize:(SEL)aSel;
+- error:(const char *)aString, ...;
+
+ /* Archiving */
++ (int)version;
++ setVersion:(int)aVersion;
++ (int)streamVersion: (TypedStream*)aStream;
+
+- read: (TypedStream*)aStream;
+- write: (TypedStream*)aStream;
+- awake;
+
+@end
+
+#endif
diff --git a/gnu/usr.bin/cc/libobjc/Object.m b/gnu/usr.bin/cc/libobjc/Object.m
new file mode 100644
index 000000000000..79bbdd8d7251
--- /dev/null
+++ b/gnu/usr.bin/cc/libobjc/Object.m
@@ -0,0 +1,358 @@
+/* The implementation of class Object for Objective-C.
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU CC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* As a special exception, if you link this library with files compiled
+ with GCC to produce an executable, this does not cause the resulting
+ executable to be covered by the GNU General Public License. This
+ exception does not however invalidate any other reasons why the
+ executable file might be covered by the GNU General Public License. */
+
+#include "objc/Object.h"
+#include "objc/Protocol.h"
+#include "objc/objc-api.h"
+
+#include "gstdarg.h"
+extern void (*_objc_error)(id object, const char *format, va_list);
+
+extern int errno;
+
+#define MAX_CLASS_NAME_LEN 256
+
+@implementation Object
+
++ initialize
+{
+ return self;
+}
+
+- init
+{
+ return self;
+}
+
++ new
+{
+ return [[self alloc] init];
+}
+
++ alloc
+{
+ return class_create_instance(self);
+}
+
+- free
+{
+ return object_dispose(self);
+}
+
+- copy
+{
+ return [[self shallowCopy] deepen];
+}
+
+- shallowCopy
+{
+ return object_copy(self);
+}
+
+- deepen
+{
+ return self;
+}
+
+- deepCopy
+{
+ return [self copy];
+}
+
+- (Class*)class
+{
+ return object_get_class(self);
+}
+
+- (Class*)superClass
+{
+ return object_get_super_class(self);
+}
+
+- (MetaClass*)metaClass
+{
+ return object_get_meta_class(self);
+}
+
+- (const char *)name
+{
+ return object_get_class_name(self);
+}
+
+- self
+{
+ return self;
+}
+
+- (unsigned int)hash
+{
+ return (size_t)self;
+}
+
+- (BOOL)isEqual:anObject
+{
+ return self==anObject;
+}
+
+- (BOOL)isMetaClass
+{
+ return NO;
+}
+
+- (BOOL)isClass
+{
+ return object_is_class(self);
+}
+
+- (BOOL)isInstance
+{
+ return object_is_instance(self);
+}
+
+- (BOOL)isKindOf:(Class*)aClassObject
+{
+ Class* class;
+
+ for (class = self->isa; class!=Nil; class = class_get_super_class(class))
+ if (class==aClassObject)
+ return YES;
+ return NO;
+}
+
+- (BOOL)isMemberOf:(Class*)aClassObject
+{
+ return self->isa==aClassObject;
+}
+
+- (BOOL)isKindOfClassNamed:(const char *)aClassName
+{
+ Class* class;
+
+ if (aClassName!=NULL)
+ for (class = self->isa; class!=Nil; class = class_get_super_class(class))
+ if (!strcmp(class_get_class_name(class), aClassName))
+ return YES;
+ return NO;
+}
+
+- (BOOL)isMemberOfClassNamed:(const char *)aClassName
+{
+ return ((aClassName!=NULL)
+ &&!strcmp(class_get_class_name(self->isa), aClassName));
+}
+
++ (BOOL)instancesRespondTo:(SEL)aSel
+{
+ return class_get_instance_method(self, aSel)!=METHOD_NULL;
+}
+
+- (BOOL)respondsTo:(SEL)aSel
+{
+ return ((object_is_instance(self)
+ ?class_get_instance_method(self->isa, aSel)
+ :class_get_class_method(self->isa, aSel))!=METHOD_NULL);
+}
+
++ (IMP)instanceMethodFor:(SEL)aSel
+{
+ return method_get_imp(class_get_instance_method(self, aSel));
+}
+
+// Indicates if the receiving class or instance conforms to the given protocol
+// not usually overridden by subclasses
+- (BOOL) conformsTo: (Protocol*)aProtocol
+{
+ int i;
+ struct objc_protocol_list* proto_list;
+
+ for (proto_list = isa->protocols;
+ proto_list; proto_list = proto_list->next)
+ {
+ for (i=0; i < proto_list->count; i++)
+ {
+ if ([proto_list->list[i] conformsTo: aProtocol])
+ return YES;
+ }
+ }
+
+ if ([self superClass])
+ return [[self superClass] conformsTo: aProtocol];
+ else
+ return NO;
+}
+
+- (IMP)methodFor:(SEL)aSel
+{
+ return (method_get_imp(object_is_instance(self)
+ ?class_get_instance_method(self->isa, aSel)
+ :class_get_class_method(self->isa, aSel)));
+}
+
++ (struct objc_method_description *)descriptionForInstanceMethod:(SEL)aSel
+{
+ return ((struct objc_method_description *)
+ class_get_instance_method(self, aSel));
+}
+
+- (struct objc_method_description *)descriptionForMethod:(SEL)aSel
+{
+ return ((struct objc_method_description *)
+ (object_is_instance(self)
+ ?class_get_instance_method(self->isa, aSel)
+ :class_get_class_method(self->isa, aSel)));
+}
+
+- perform:(SEL)aSel
+{
+ IMP msg = objc_msg_lookup(self, aSel);
+ if (!msg)
+ return [self error:"invalid selector passed to %s", sel_get_name(_cmd)];
+ return (*msg)(self, aSel);
+}
+
+- perform:(SEL)aSel with:anObject
+{
+ IMP msg = objc_msg_lookup(self, aSel);
+ if (!msg)
+ return [self error:"invalid selector passed to %s", sel_get_name(_cmd)];
+ return (*msg)(self, aSel, anObject);
+}
+
+- perform:(SEL)aSel with:anObject1 with:anObject2
+{
+ IMP msg = objc_msg_lookup(self, aSel);
+ if (!msg)
+ return [self error:"invalid selector passed to %s", sel_get_name(_cmd)];
+ return (*msg)(self, aSel, anObject1, anObject2);
+}
+
+- forward:(SEL)aSel :(arglist_t)argFrame
+{
+ return [self doesNotRecognize: aSel];
+}
+
+- performv:(SEL)aSel :(arglist_t)argFrame
+{
+ return objc_msg_sendv(self, aSel, method_get_argsize(0), argFrame);
+}
+
++ poseAs:(Class*)aClassObject
+{
+ return class_pose_as(self, aClassObject);
+}
+
+- (Class*)transmuteClassTo:(Class*)aClassObject
+{
+ if (object_is_instance(self))
+ if (class_is_class(aClassObject))
+ if (class_get_instance_size(aClassObject)==class_get_instance_size(isa))
+ if ([self isKindOf:aClassObject])
+ {
+ Class* old_isa = isa;
+ isa = aClassObject;
+ return old_isa;
+ }
+ return nil;
+}
+
+- subclassResponsibility:(SEL)aSel
+{
+ return [self error:"subclass should override %s", sel_get_name(aSel)];
+}
+
+- notImplemented:(SEL)aSel
+{
+ return [self error:"method %s not implemented", sel_get_name(aSel)];
+}
+
+- doesNotRecognize:(SEL)aSel
+{
+ return [self error:"%s does not recognize %s",
+ object_get_class_name(self), sel_get_name(aSel)];
+}
+
+- error:(const char *)aString, ...
+{
+#define FMT "error: %s (%s)\n%s\n"
+ char fmt[(strlen((char*)FMT)+strlen((char*)object_get_class_name(self))
+ +((aString!=NULL)?strlen((char*)aString):0)+8)];
+ va_list ap;
+
+ sprintf(fmt, FMT, object_get_class_name(self),
+ object_is_instance(self)?"instance":"class",
+ (aString!=NULL)?aString:"");
+ va_start(ap, aString);
+ (*_objc_error)(self, fmt, ap);
+ va_end(ap);
+ return nil;
+#undef FMT
+}
+
++ (int)version
+{
+ return class_get_version(self);
+}
+
++ setVersion:(int)aVersion
+{
+ class_set_version(self, aVersion);
+ return self;
+}
+
++ (int)streamVersion: (TypedStream*)aStream
+{
+#ifndef __alpha__
+ if (aStream->mode == OBJC_READONLY)
+ return objc_get_stream_class_version (aStream, self);
+ else
+#endif
+ return class_get_version (self);
+}
+
+// These are used to write or read the instance variables
+// declared in this particular part of the object. Subclasses
+// should extend these, by calling [super read/write: aStream]
+// before doing their own archiving. These methods are private, in
+// the sense that they should only be called from subclasses.
+
+- read: (TypedStream*)aStream
+{
+ // [super read: aStream];
+ return self;
+}
+
+- write: (TypedStream*)aStream
+{
+ // [super write: aStream];
+ return self;
+}
+
+- awake
+{
+ // [super awake];
+ return self;
+}
+
+@end
diff --git a/gnu/usr.bin/cc/libobjc/Protocol.h b/gnu/usr.bin/cc/libobjc/Protocol.h
new file mode 100644
index 000000000000..6a38b4838c0c
--- /dev/null
+++ b/gnu/usr.bin/cc/libobjc/Protocol.h
@@ -0,0 +1,57 @@
+/* Declare the class Protocol for Objective C programs.
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* As a special exception, if you link this library with files
+ compiled with GCC to produce an executable, this does not cause
+ the resulting executable to be covered by the GNU General Public License.
+ This exception does not however invalidate any other reasons why
+ the executable file might be covered by the GNU General Public License. */
+
+#ifndef __Protocol_INCLUDE_GNU
+#define __Protocol_INCLUDE_GNU
+
+#include "objc/Object.h"
+
+@interface Protocol : Object
+{
+@private
+ char *protocol_name;
+ struct objc_protocol_list *protocol_list;
+ struct objc_method_description_list *instance_methods, *class_methods;
+}
+
+/* Obtaining attributes intrinsic to the protocol */
+
+- (const char *)name;
+
+/* Testing protocol conformance */
+
+- (BOOL) conformsTo: (Protocol *)aProtocolObject;
+
+/* Looking up information specific to a protocol */
+
+- (struct objc_method_description *) descriptionForInstanceMethod:(SEL)aSel;
+- (struct objc_method_description *) descriptionForClassMethod:(SEL)aSel;
+
+@end
+
+
+
+
+#endif __Protocol_INCLUDE_GNU
diff --git a/gnu/usr.bin/cc/libobjc/Protocol.m b/gnu/usr.bin/cc/libobjc/Protocol.m
new file mode 100644
index 000000000000..38963d0d4bfd
--- /dev/null
+++ b/gnu/usr.bin/cc/libobjc/Protocol.m
@@ -0,0 +1,127 @@
+/* This file contains the implementation of class Protocol.
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* As a special exception, if you link this library with files
+ compiled with GCC to produce an executable, this does not cause
+ the resulting executable to be covered by the GNU General Public License.
+ This exception does not however invalidate any other reasons why
+ the executable file might be covered by the GNU General Public License. */
+
+#include "objc/Protocol.h"
+#include "objc/objc-api.h"
+
+/* Method description list */
+struct objc_method_description_list {
+ int count;
+ struct objc_method_description list[1];
+};
+
+
+@implementation Protocol
+{
+@private
+ char *protocol_name;
+ struct objc_protocol_list *protocol_list;
+ struct objc_method_description_list *instance_methods, *class_methods;
+}
+
+/* Obtaining attributes intrinsic to the protocol */
+
+- (const char *)name
+{
+ return protocol_name;
+}
+
+/* Testing protocol conformance */
+
+- (BOOL) conformsTo: (Protocol *)aProtocolObject
+{
+ int i;
+ struct objc_protocol_list* proto_list;
+
+ if (!strcmp(aProtocolObject->protocol_name, self->protocol_name))
+ return YES;
+
+ for (proto_list = protocol_list; proto_list; proto_list = proto_list->next)
+ {
+ for (i=0; i < proto_list->count; i++)
+ {
+ if ([proto_list->list[i] conformsTo: aProtocolObject])
+ return YES;
+ }
+ }
+
+ return NO;
+}
+
+/* Looking up information specific to a protocol */
+
+- (struct objc_method_description *) descriptionForInstanceMethod:(SEL)aSel
+{
+ int i;
+ struct objc_protocol_list* proto_list;
+ const char* name = sel_get_name (aSel);
+ struct objc_method_description *result;
+
+ for (i = 0; i < instance_methods->count; i++)
+ {
+ if (!strcmp ((char*)instance_methods->list[i].name, name))
+ return &(instance_methods->list[i]);
+ }
+
+ for (proto_list = protocol_list; proto_list; proto_list = proto_list->next)
+ {
+ for (i=0; i < proto_list->count; i++)
+ {
+ if ((result = [proto_list->list[i]
+ descriptionForInstanceMethod: aSel]))
+ return result;
+ }
+ }
+
+ return NULL;
+}
+
+- (struct objc_method_description *) descriptionForClassMethod:(SEL)aSel;
+{
+ int i;
+ struct objc_protocol_list* proto_list;
+ const char* name = sel_get_name (aSel);
+ struct objc_method_description *result;
+
+ for (i = 0; i < class_methods->count; i++)
+ {
+ if (!strcmp ((char*)class_methods->list[i].name, name))
+ return &(class_methods->list[i]);
+ }
+
+ for (proto_list = protocol_list; proto_list; proto_list = proto_list->next)
+ {
+ for (i=0; i < proto_list->count; i++)
+ {
+ if ((result = [proto_list->list[i]
+ descriptionForClassMethod: aSel]))
+ return result;
+ }
+ }
+
+ return NULL;
+}
+
+@end
diff --git a/gnu/usr.bin/cc/libobjc/archive.c b/gnu/usr.bin/cc/libobjc/archive.c
new file mode 100644
index 000000000000..867b74977f3b
--- /dev/null
+++ b/gnu/usr.bin/cc/libobjc/archive.c
@@ -0,0 +1,1492 @@
+/* GNU Objective C Runtime archiving
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+Author: Kresten Krab Thorup
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2, or (at your option) any later version.
+
+GNU CC 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 General Public License for more
+ details.
+
+You should have received a copy of the GNU General Public License along with
+ GNU CC; see the file COPYING. If not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* As a special exception, if you link this library with files compiled with
+ GCC to produce an executable, this does not cause the resulting executable
+ to be covered by the GNU General Public License. This exception does not
+ however invalidate any other reasons why the executable file might be
+ covered by the GNU General Public License. */
+
+/*
+** Note: This version assumes that int and longs are both 32bit.
+*/
+
+#ifndef __alpha__
+
+#include "runtime.h"
+#include "typedstream.h"
+
+#define __objc_fatal(format, args...) \
+ { fprintf(stderr, "archining: "); \
+ fprintf(stderr, format, ## args); \
+ fprintf(stderr, "\n"); abort(); }
+
+/* Declare some functions... */
+
+static int
+objc_read_class (struct objc_typed_stream* stream, Class** class);
+
+static int
+objc_sizeof_type(const char* type);
+
+static int
+objc_write_use_common (struct objc_typed_stream* stream, unsigned int key);
+
+static int
+objc_write_register_common (struct objc_typed_stream* stream,
+ unsigned int key);
+
+static int
+objc_write_class (struct objc_typed_stream* stream,
+ struct objc_class* class);
+
+static const char*
+__objc_skip_type (const char* type);
+
+static void __objc_finish_write_root_object(struct objc_typed_stream*);
+static void __objc_finish_read_root_object(struct objc_typed_stream*);
+
+static __inline__ int
+__objc_code_unsigned_char (unsigned char* buf, unsigned char val)
+{
+ if ((val&_B_VALUE) == val)
+ {
+ buf[0] = val|_B_SINT;
+ return 1;
+ }
+ else
+ {
+ buf[0] = _B_NINT|0x01;
+ buf[1] = val;
+ return 2;
+ }
+}
+
+int
+objc_write_unsigned_char (struct objc_typed_stream* stream,
+ unsigned char value)
+{
+ unsigned char buf[sizeof (unsigned char)+1];
+ int len = __objc_code_unsigned_char (buf, value);
+ return (*stream->write)(stream->physical, buf, len);
+}
+
+static __inline__ int
+__objc_code_char (unsigned char* buf, char val)
+{
+ if (val >= 0)
+ return __objc_code_unsigned_char (buf, val);
+ else
+ {
+ buf[0] = _B_NINT|_B_SIGN|0x01;
+ buf[1] = -val;
+ return 2;
+ }
+}
+
+int
+objc_write_char (struct objc_typed_stream* stream, char value)
+{
+ unsigned char buf[sizeof (char)+1];
+ int len = __objc_code_char (buf, value);
+ return (*stream->write)(stream->physical, buf, len);
+}
+
+static __inline__ int
+__objc_code_unsigned_short (unsigned char* buf, unsigned short val)
+{
+ if (val <= 0xffU)
+ return __objc_code_unsigned_char (buf, val);
+
+ else
+ {
+ buf[0] = _B_NINT|0x02;
+ buf[1] = val/0x100;
+ buf[2] = val%0x100;
+ return 3;
+ }
+}
+
+int
+objc_write_unsigned_short (struct objc_typed_stream* stream, unsigned short value)
+{
+ unsigned char buf[sizeof (unsigned short)+1];
+ int len = __objc_code_unsigned_short (buf, value);
+ return (*stream->write)(stream->physical, buf, len);
+}
+
+static __inline__ int
+__objc_code_short (unsigned char* buf, short val)
+{
+ if (val > 0)
+ return __objc_code_unsigned_short (buf, val);
+
+ if (val > -0x7f) /* val > -128 */
+ return __objc_code_char (buf, val);
+
+ else
+ {
+ int len = __objc_code_unsigned_short (buf, -val);
+ buf[0] |= _B_SIGN;
+ return len;
+ }
+}
+
+int
+objc_write_short (struct objc_typed_stream* stream, short value)
+{
+ unsigned char buf[sizeof (short)+1];
+ int len = __objc_code_short (buf, value);
+ return (*stream->write)(stream->physical, buf, len);
+}
+
+
+static __inline__ int
+__objc_code_unsigned_int (unsigned char* buf, unsigned int val)
+{
+ if (val < 0x10000)
+ return __objc_code_unsigned_short (buf, val%0x10000);
+
+ else if (val < 0x1000000)
+ {
+ buf[0] = _B_NINT|3;
+ buf[1] = val/0x10000;
+ buf[2] = (val%0x10000)/0x100;
+ buf[3] = val%0x100;
+ return 4;
+ }
+
+ else
+ {
+ buf[0] = _B_NINT|4;
+ buf[1] = val/0x1000000;
+ buf[2] = (val%0x1000000)/0x10000;
+ buf[3] = (val%0x10000)/0x100;
+ buf[4] = val%0x100;
+ return 5;
+ }
+}
+
+int
+objc_write_unsigned_int (struct objc_typed_stream* stream, unsigned int value)
+{
+ unsigned char buf[sizeof(unsigned int)+1];
+ int len = __objc_code_unsigned_int (buf, value);
+ return (*stream->write)(stream->physical, buf, len);
+}
+
+static __inline__ int
+__objc_code_int (unsigned char* buf, int val)
+{
+ if (val >= 0)
+ return __objc_code_unsigned_int (buf, val);
+
+ if (val > -0x7f)
+ return __objc_code_char (buf, val);
+
+ else
+ {
+ int len = __objc_code_unsigned_int (buf, -val);
+ buf[0] |= _B_SIGN;
+ return len;
+ }
+}
+
+int
+objc_write_int (struct objc_typed_stream* stream, int value)
+{
+ unsigned char buf[sizeof(int)+1];
+ int len = __objc_code_int (buf, value);
+ return (*stream->write)(stream->physical, buf, len);
+}
+
+int
+objc_write_string (struct objc_typed_stream* stream,
+ const unsigned char* string, unsigned int nbytes)
+{
+ unsigned char buf[sizeof(unsigned int)+1];
+ int len = __objc_code_unsigned_int (buf, nbytes);
+
+ if ((buf[0]&_B_CODE) == _B_SINT)
+ buf[0] = (buf[0]&_B_VALUE)|_B_SSTR;
+
+ else /* _B_NINT */
+ buf[0] = (buf[0]&_B_VALUE)|_B_NSTR;
+
+ if ((*stream->write)(stream->physical, buf, len) != 0)
+ return (*stream->write)(stream->physical, string, nbytes);
+ else
+ return 0;
+}
+
+int
+objc_write_string_atomic (struct objc_typed_stream* stream,
+ unsigned char* string, unsigned int nbytes)
+{
+ unsigned int key;
+ if ((key = (unsigned int)hash_value_for_key (stream->stream_table, string)))
+ return objc_write_use_common (stream, key);
+ else
+ {
+ int length;
+ hash_add (&stream->stream_table, (void*)key=(unsigned int)string, string);
+ if ((length = objc_write_register_common (stream, key)))
+ return objc_write_string (stream, string, nbytes);
+ return length;
+ }
+}
+
+static int
+objc_write_register_common (struct objc_typed_stream* stream, unsigned int key)
+{
+ unsigned char buf[sizeof (unsigned int)+2];
+ int len = __objc_code_unsigned_int (buf+1, key);
+ if (len == 1)
+ {
+ buf[0] = _B_RCOMM|0x01;
+ buf[1] &= _B_VALUE;
+ return (*stream->write)(stream->physical, buf, len+1);
+ }
+ else
+ {
+ buf[1] = (buf[1]&_B_VALUE)|_B_RCOMM;
+ return (*stream->write)(stream->physical, buf+1, len);
+ }
+}
+
+static int
+objc_write_use_common (struct objc_typed_stream* stream, unsigned int key)
+{
+ unsigned char buf[sizeof (unsigned int)+2];
+ int len = __objc_code_unsigned_int (buf+1, key);
+ if (len == 1)
+ {
+ buf[0] = _B_UCOMM|0x01;
+ buf[1] &= _B_VALUE;
+ return (*stream->write)(stream->physical, buf, 2);
+ }
+ else
+ {
+ buf[1] = (buf[1]&_B_VALUE)|_B_UCOMM;
+ return (*stream->write)(stream->physical, buf+1, len);
+ }
+}
+
+static __inline__ int
+__objc_write_extension (struct objc_typed_stream* stream, unsigned char code)
+{
+ if (code <= _B_VALUE)
+ {
+ unsigned char buf = code|_B_EXT;
+ return (*stream->write)(stream->physical, &buf, 1);
+ }
+ else
+ abort();
+}
+
+__inline__ int
+__objc_write_object (struct objc_typed_stream* stream, id object)
+{
+ unsigned char buf = '\0';
+ SEL write_sel = sel_get_uid ("write:");
+ if (object)
+ {
+ __objc_write_extension (stream, _BX_OBJECT);
+ objc_write_class (stream, object->class_pointer);
+ (*objc_msg_lookup(object, write_sel))(object, write_sel, stream);
+ return (*stream->write)(stream->physical, &buf, 1);
+ }
+ else
+ return objc_write_use_common(stream, 0);
+}
+
+int
+objc_write_object_reference (struct objc_typed_stream* stream, id object)
+{
+ unsigned int key;
+ if ((key = (unsigned int)hash_value_for_key (stream->object_table, object)))
+ return objc_write_use_common (stream, key);
+
+ __objc_write_extension (stream, _BX_OBJREF);
+ return objc_write_unsigned_int (stream, (unsigned int)object);
+}
+
+int
+objc_write_root_object (struct objc_typed_stream* stream, id object)
+{
+ int len;
+ if (stream->writing_root_p)
+ __objc_fatal ("objc_write_root_object called recursively")
+ else
+ {
+ stream->writing_root_p = 1;
+ __objc_write_extension (stream, _BX_OBJROOT);
+ if((len = objc_write_object (stream, object)))
+ __objc_finish_write_root_object(stream);
+ stream->writing_root_p = 0;
+ }
+ return len;
+}
+
+int
+objc_write_object (struct objc_typed_stream* stream, id object)
+{
+ unsigned int key;
+ if ((key = (unsigned int)hash_value_for_key (stream->object_table, object)))
+ return objc_write_use_common (stream, key);
+
+ else if (object == nil)
+ return objc_write_use_common(stream, 0);
+
+ else
+ {
+ int length;
+ hash_add (&stream->object_table, (void*)key=(unsigned int)object, object);
+ if ((length = objc_write_register_common (stream, key)))
+ return __objc_write_object (stream, object);
+ return length;
+ }
+}
+
+__inline__ int
+__objc_write_class (struct objc_typed_stream* stream, struct objc_class* class)
+{
+ __objc_write_extension (stream, _BX_CLASS);
+ objc_write_string_atomic(stream, (char*)class->name,
+ strlen((char*)class->name));
+ return objc_write_unsigned_int (stream, CLS_GETNUMBER(class));
+}
+
+
+static int
+objc_write_class (struct objc_typed_stream* stream,
+ struct objc_class* class)
+{
+ unsigned int key;
+ if ((key = (unsigned int)hash_value_for_key (stream->stream_table, class)))
+ return objc_write_use_common (stream, key);
+ else
+ {
+ int length;
+ hash_add (&stream->stream_table, (void*)key=(unsigned int)class, class);
+ if ((length = objc_write_register_common (stream, key)))
+ return __objc_write_class (stream, class);
+ return length;
+ }
+}
+
+
+__inline__ int
+__objc_write_selector (struct objc_typed_stream* stream, SEL selector)
+{
+ const char* sel_name = sel_get_name (selector);
+ __objc_write_extension (stream, _BX_SEL);
+ return objc_write_string (stream, sel_name, strlen ((char*)sel_name));
+}
+
+int
+objc_write_selector (struct objc_typed_stream* stream, SEL selector)
+{
+ const char* sel_name = sel_get_name (selector);
+ unsigned int key;
+ if ((key = (unsigned int)hash_value_for_key (stream->stream_table, sel_name)))
+ return objc_write_use_common (stream, key);
+ else
+ {
+ int length;
+ hash_add (&stream->stream_table, (void*)key=(unsigned int)sel_name, (char*)sel_name);
+ if ((length = objc_write_register_common (stream, key)))
+ return __objc_write_selector (stream, selector);
+ return length;
+ }
+}
+
+
+
+/*
+** Read operations
+*/
+
+__inline__ int
+objc_read_char (struct objc_typed_stream* stream, char* val)
+{
+ unsigned char buf;
+ int len;
+ len = (*stream->read)(stream->physical, &buf, 1);
+ if (len != 0)
+ {
+ if ((buf & _B_CODE) == _B_SINT)
+ (*val) = (buf & _B_VALUE);
+
+ else if ((buf & _B_NUMBER) == 1)
+ {
+ len = (*stream->read)(stream->physical, val, 1);
+ if (buf&_B_SIGN)
+ (*val) = -1*(*val);
+ }
+
+ else
+ __objc_fatal("expected 8bit signed int, got %dbit int",
+ (int)(buf&_B_NUMBER)*8);
+ }
+ return len;
+}
+
+
+__inline__ int
+objc_read_unsigned_char (struct objc_typed_stream* stream, unsigned char* val)
+{
+ unsigned char buf;
+ int len;
+ if ((len = (*stream->read)(stream->physical, &buf, 1)))
+ {
+ if ((buf & _B_CODE) == _B_SINT)
+ (*val) = (buf & _B_VALUE);
+
+ else if ((buf & _B_NUMBER) == 1)
+ len = (*stream->read)(stream->physical, val, 1);
+
+ else
+ __objc_fatal("expected 8bit unsigned int, got %dbit int",
+ (int)(buf&_B_NUMBER)*8);
+ }
+ return len;
+}
+
+__inline__ int
+objc_read_short (struct objc_typed_stream* stream, short* value)
+{
+ unsigned char buf[sizeof(short)+1];
+ int len;
+ if ((len = (*stream->read)(stream->physical, buf, 1)))
+ {
+ if ((buf[0] & _B_CODE) == _B_SINT)
+ (*value) = (buf[0] & _B_VALUE);
+
+ else
+ {
+ int pos = 1;
+ int nbytes = buf[0] & _B_NUMBER;
+ if (nbytes > sizeof (short))
+ __objc_fatal("expected short, got bigger (%dbits)", nbytes*8);
+ len = (*stream->read)(stream->physical, buf+1, nbytes);
+ (*value) = 0;
+ while (pos <= nbytes)
+ (*value) = ((*value)*0x100) + buf[pos++];
+ if (buf[0] & _B_SIGN)
+ (*value) = -(*value);
+ }
+ }
+ return len;
+}
+
+__inline__ int
+objc_read_unsigned_short (struct objc_typed_stream* stream,
+ unsigned short* value)
+{
+ unsigned char buf[sizeof(unsigned short)+1];
+ int len;
+ if ((len = (*stream->read)(stream->physical, buf, 1)))
+ {
+ if ((buf[0] & _B_CODE) == _B_SINT)
+ (*value) = (buf[0] & _B_VALUE);
+
+ else
+ {
+ int pos = 1;
+ int nbytes = buf[0] & _B_NUMBER;
+ if (nbytes > sizeof (short))
+ __objc_fatal("expected short, got int or bigger");
+ len = (*stream->read)(stream->physical, buf+1, nbytes);
+ (*value) = 0;
+ while (pos <= nbytes)
+ (*value) = ((*value)*0x100) + buf[pos++];
+ }
+ }
+ return len;
+}
+
+
+__inline__ int
+objc_read_int (struct objc_typed_stream* stream, int* value)
+{
+ unsigned char buf[sizeof(int)+1];
+ int len;
+ if ((len = (*stream->read)(stream->physical, buf, 1)))
+ {
+ if ((buf[0] & _B_CODE) == _B_SINT)
+ (*value) = (buf[0] & _B_VALUE);
+
+ else
+ {
+ int pos = 1;
+ int nbytes = buf[0] & _B_NUMBER;
+ if (nbytes > sizeof (int))
+ __objc_fatal("expected int, got bigger");
+ len = (*stream->read)(stream->physical, buf+1, nbytes);
+ (*value) = 0;
+ while (pos <= nbytes)
+ (*value) = ((*value)*0x100) + buf[pos++];
+ if (buf[0] & _B_SIGN)
+ (*value) = -(*value);
+ }
+ }
+ return len;
+}
+
+__inline__ int
+__objc_read_nbyte_uint (struct objc_typed_stream* stream,
+ unsigned int nbytes, unsigned int* val)
+{
+ int len, pos = 0;
+ unsigned char buf[sizeof(unsigned int)+1];
+
+ if (nbytes > sizeof (int))
+ __objc_fatal("expected int, got bigger");
+
+ len = (*stream->read)(stream->physical, buf, nbytes);
+ (*val) = 0;
+ while (pos < nbytes)
+ (*val) = ((*val)*0x100) + buf[pos++];
+ return len;
+}
+
+
+__inline__ int
+objc_read_unsigned_int (struct objc_typed_stream* stream,
+ unsigned int* value)
+{
+ unsigned char buf[sizeof(unsigned int)+1];
+ int len;
+ if ((len = (*stream->read)(stream->physical, buf, 1)))
+ {
+ if ((buf[0] & _B_CODE) == _B_SINT)
+ (*value) = (buf[0] & _B_VALUE);
+
+ else
+ len = __objc_read_nbyte_uint (stream, (buf[0] & _B_VALUE), value);
+
+ }
+ return len;
+}
+
+__inline__ int
+objc_read_string (struct objc_typed_stream* stream,
+ char** string)
+{
+ unsigned char buf[sizeof(unsigned int)+1];
+ int len;
+ if ((len = (*stream->read)(stream->physical, buf, 1)))
+ {
+ unsigned int key = 0;
+
+ if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
+ {
+ len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
+ len = (*stream->read)(stream->physical, buf, 1);
+ }
+
+ switch (buf[0]&_B_CODE) {
+ case _B_SSTR:
+ {
+ int length = buf[0]&_B_VALUE;
+ (*string) = (char*)__objc_xmalloc(length+1);
+ if (key)
+ hash_add (&stream->stream_table, (void*)key, *string);
+ len = (*stream->read)(stream->physical, *string, length);
+ (*string)[length] = '\0';
+ }
+ break;
+
+ case _B_UCOMM:
+ {
+ len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
+ (*string) = hash_value_for_key (stream->stream_table, (void*)key);
+ }
+ break;
+
+ case _B_NSTR:
+ {
+ unsigned int nbytes = buf[0]&_B_VALUE;
+ len = __objc_read_nbyte_uint(stream, nbytes, &nbytes);
+ if (len) {
+ (*string) = (char*)__objc_xmalloc(nbytes);
+ if (key)
+ hash_add (&stream->stream_table, (void*)key, *string);
+ len = (*stream->read)(stream->physical, *string, buf[0]&_B_VALUE);
+ (*string)[nbytes] = '\0';
+ }
+ }
+ break;
+
+ default:
+ __objc_fatal("expected string, got opcode %c\n", (buf[0]&_B_CODE));
+ }
+ }
+
+ return len;
+}
+
+
+int
+objc_read_object (struct objc_typed_stream* stream, id* object)
+{
+ unsigned char buf[sizeof (unsigned int)];
+ int len;
+ if ((len = (*stream->read)(stream->physical, buf, 1)))
+ {
+ SEL read_sel = sel_get_uid ("read:");
+ unsigned int key = 0;
+
+ if ((buf[0]&_B_CODE) == _B_RCOMM) /* register common */
+ {
+ len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
+ len = (*stream->read)(stream->physical, buf, 1);
+ }
+
+ if (buf[0] == (_B_EXT | _BX_OBJECT))
+ {
+ Class* class;
+
+ /* get class */
+ len = objc_read_class (stream, &class);
+
+ /* create instance */
+ (*object) = class_create_instance(class);
+
+ /* register? */
+ if (key)
+ hash_add (&stream->object_table, (void*)key, *object);
+
+ /* send -read: */
+ if (__objc_responds_to (*object, read_sel))
+ (*get_imp(class, read_sel))(*object, read_sel, stream);
+
+ /* check null-byte */
+ len = (*stream->read)(stream->physical, buf, 1);
+ if (buf[0] != '\0')
+ __objc_fatal("expected null-byte, got opcode %c", buf[0]);
+ }
+
+ else if ((buf[0]&_B_CODE) == _B_UCOMM)
+ {
+ if (key)
+ __objc_fatal("cannot register use upcode...");
+ len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
+ (*object) = hash_value_for_key (stream->object_table, (void*)key);
+ }
+
+ else if (buf[0] == (_B_EXT | _BX_OBJREF)) /* a forward reference */
+ {
+ struct objc_list* other;
+ len = objc_read_unsigned_int (stream, &key);
+ other = (struct objc_list*)hash_value_for_key (stream->object_refs, (void*)key);
+ hash_add (&stream->object_refs, (void*)key, (void*)list_cons(object, other));
+ }
+
+ else if (buf[0] == (_B_EXT | _BX_OBJROOT)) /* a root object */
+ {
+ if (key)
+ __objc_fatal("cannot register root object...");
+ len = objc_read_object (stream, object);
+ __objc_finish_read_root_object (stream);
+ }
+
+ else
+ __objc_fatal("expected object, got opcode %c", buf[0]);
+ }
+ return len;
+}
+
+static int
+objc_read_class (struct objc_typed_stream* stream, Class** class)
+{
+ unsigned char buf[sizeof (unsigned int)];
+ int len;
+ if ((len = (*stream->read)(stream->physical, buf, 1)))
+ {
+ unsigned int key = 0;
+
+ if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
+ {
+ len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
+ len = (*stream->read)(stream->physical, buf, 1);
+ }
+
+ if (buf[0] == (_B_EXT | _BX_CLASS))
+ {
+ char* class_name;
+ int version;
+
+ /* get class */
+ len = objc_read_string (stream, &class_name);
+ (*class) = objc_get_class(class_name);
+ free (class_name);
+
+ /* register */
+ if (key)
+ hash_add (&stream->stream_table, (void*)key, *class);
+
+ objc_read_unsigned_int(stream, &version);
+ hash_add (&stream->class_table, (*class)->name, (void*)version);
+ }
+
+ else if ((buf[0]&_B_CODE) == _B_UCOMM)
+ {
+ if (key)
+ __objc_fatal("cannot register use upcode...");
+ len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
+ (*class) = hash_value_for_key (stream->stream_table, (void*)key);
+ if (!*class)
+ __objc_fatal("cannot find class for key %x", key);
+ }
+
+ else
+ __objc_fatal("expected class, got opcode %c", buf[0]);
+ }
+ return len;
+}
+
+int
+objc_read_selector (struct objc_typed_stream* stream, SEL* selector)
+{
+ unsigned char buf[sizeof (unsigned int)];
+ int len;
+ if ((len = (*stream->read)(stream->physical, buf, 1)))
+ {
+ unsigned int key = 0;
+
+ if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */
+ {
+ len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
+ len = (*stream->read)(stream->physical, buf, 1);
+ }
+
+ if (buf[0] == (_B_EXT|_BX_SEL)) /* selector! */
+ {
+ char* selector_name;
+
+ /* get selector */
+ len = objc_read_string (stream, &selector_name);
+ (*selector) = sel_get_uid(selector_name);
+ free (selector_name);
+
+ /* register */
+ if (key)
+ hash_add (&stream->stream_table, (void*)key, *selector);
+ }
+
+ else if ((buf[0]&_B_CODE) == _B_UCOMM)
+ {
+ if (key)
+ __objc_fatal("cannot register use upcode...");
+ len = __objc_read_nbyte_uint(stream, (buf[0] & _B_VALUE), &key);
+ (*selector) = hash_value_for_key (stream->stream_table, (void*)key);
+ }
+
+ else
+ __objc_fatal("expected selector, got opcode %c", buf[0]);
+ }
+ return len;
+}
+
+static int
+objc_sizeof_type(const char* type)
+{
+ switch(*type) {
+ case _C_ID: return sizeof(id);
+ break;
+
+ case _C_CLASS:
+ return sizeof(Class*);
+ break;
+
+ case _C_SEL:
+ return sizeof(SEL);
+ break;
+
+ case _C_CHR:
+ return sizeof(char);
+ break;
+
+ case _C_UCHR:
+ return sizeof(unsigned char);
+ break;
+
+ case _C_SHT:
+ return sizeof(short);
+ break;
+
+ case _C_USHT:
+ return sizeof(unsigned short);
+ break;
+
+ case _C_INT:
+ case _C_LNG:
+ return sizeof(int);
+ break;
+
+ case _C_UINT:
+ case _C_ULNG:
+ return sizeof(unsigned int);
+ break;
+
+ case _C_ATOM:
+ case _C_CHARPTR:
+ return sizeof(char*);
+ break;
+
+ default:
+ fprintf(stderr, "objc_write_type: cannot parse typespec: %s\n", type);
+ abort();
+ }
+}
+
+
+static const char*
+__objc_skip_type (const char* type)
+{
+ switch (*type) {
+ case _C_ID:
+ case _C_CLASS:
+ case _C_SEL:
+ case _C_CHR:
+ case _C_UCHR:
+ case _C_CHARPTR:
+ case _C_ATOM:
+ case _C_SHT:
+ case _C_USHT:
+ case _C_INT:
+ case _C_UINT:
+ case _C_LNG:
+ case _C_ULNG:
+ case _C_FLT:
+ case _C_DBL:
+ return ++type;
+ break;
+
+ case _C_ARY_B:
+ while(isdigit(*++type));
+ type = __objc_skip_type(type);
+ if (*type == _C_ARY_E)
+ return ++type;
+ else
+ __objc_fatal("cannot parse typespec: %s", type);
+ break;
+
+ default:
+ fprintf(stderr, "objc_read_types: cannot parse typespec: %s\n", type);
+ abort();
+ }
+}
+
+/*
+** USER LEVEL FUNCTIONS
+*/
+
+/*
+** Write one object, encoded in TYPE and pointed to by DATA to the
+** typed stream STREAM.
+*/
+
+int
+objc_write_type(TypedStream* stream, const char* type, const void* data)
+{
+ switch(*type) {
+ case _C_ID:
+ return objc_write_object (stream, *(id*)data);
+ break;
+
+ case _C_CLASS:
+ return objc_write_class (stream, *(Class**)data);
+ break;
+
+ case _C_SEL:
+ return objc_write_selector (stream, *(SEL*)data);
+ break;
+
+ case _C_CHR:
+ return objc_write_char(stream, *(char*)data);
+ break;
+
+ case _C_UCHR:
+ return objc_write_unsigned_char(stream, *(unsigned char*)data);
+ break;
+
+ case _C_SHT:
+ return objc_write_short(stream, *(short*)data);
+ break;
+
+ case _C_USHT:
+ return objc_write_unsigned_short(stream, *(unsigned short*)data);
+ break;
+
+ case _C_INT:
+ case _C_LNG:
+ return objc_write_int(stream, *(int*)data);
+ break;
+
+ case _C_UINT:
+ case _C_ULNG:
+ return objc_write_unsigned_int(stream, *(unsigned int*)data);
+ break;
+
+ case _C_CHARPTR:
+ return objc_write_string (stream, (char*)data, strlen((char*)data));
+ break;
+
+ case _C_ATOM:
+ return objc_write_string_atomic (stream, (char*)data, strlen((char*)data));
+ break;
+
+ case _C_ARY_B:
+ {
+ int len = atoi(type+1);
+ while (isdigit(*++type));
+ return objc_write_array (stream, type, len, data);
+ }
+ break;
+
+ default:
+ fprintf(stderr, "objc_write_type: cannot parse typespec: %s\n", type);
+ abort();
+ }
+}
+
+/*
+** Read one object, encoded in TYPE and pointed to by DATA to the
+** typed stream STREAM. DATA specifies the address of the types to
+** read. Expected type is checked against the type actually present
+** on the stream.
+*/
+
+int
+objc_read_type(TypedStream* stream, const char* type, void* data)
+{
+ char c;
+ switch(c = *type) {
+ case _C_ID:
+ return objc_read_object (stream, (id*)data);
+ break;
+
+ case _C_CLASS:
+ return objc_read_class (stream, (Class**)data);
+ break;
+
+ case _C_SEL:
+ return objc_read_selector (stream, (SEL*)data);
+ break;
+
+ case _C_CHR:
+ return objc_read_char (stream, (char*)data);
+ break;
+
+ case _C_UCHR:
+ return objc_read_unsigned_char (stream, (unsigned char*)data);
+ break;
+
+ case _C_SHT:
+ return objc_read_short (stream, (short*)data);
+ break;
+
+ case _C_USHT:
+ return objc_read_unsigned_short (stream, (unsigned short*)data);
+ break;
+
+ case _C_INT:
+ case _C_LNG:
+ return objc_read_int (stream, (int*)data);
+ break;
+
+ case _C_UINT:
+ case _C_ULNG:
+ return objc_read_unsigned_int (stream, (unsigned int*)data);
+ break;
+
+ case _C_CHARPTR:
+ case _C_ATOM:
+ return objc_read_string (stream, (char**)data);
+ break;
+
+ case _C_ARY_B:
+ {
+ int len = atoi(type+1);
+ while (isdigit(*++type));
+ return objc_read_array (stream, type, len, data);
+ }
+ break;
+
+ default:
+ fprintf(stderr, "objc_write_type: cannot parse typespec: %s\n", type);
+ abort();
+ }
+}
+
+/*
+** Write the object specified by the template TYPE to STREAM. Last
+** arguments specify addresses of values to be written. It might
+** seem surprising to specify values by address, but this is extremely
+** convenient for copy-paste with objc_read_types calls. A more
+** down-to-the-earth cause for this passing of addresses is that values
+** of arbitrary size is not well supported in ANSI C for functions with
+** variable number of arguments.
+*/
+
+int
+objc_write_types (TypedStream* stream, const char* type, ...)
+{
+ va_list args;
+ const char *c;
+ int res = 0;
+
+ va_start(args, type);
+
+ for (c = type; *c; c = __objc_skip_type (c))
+ {
+ switch(*c) {
+ case _C_ID:
+ res = objc_write_object (stream, *va_arg (args, id*));
+ break;
+
+ case _C_CLASS:
+ res = objc_write_class (stream, *va_arg(args, Class**));
+ break;
+
+ case _C_SEL:
+ res = objc_write_selector (stream, *va_arg(args, SEL*));
+ break;
+
+ case _C_CHR:
+ res = objc_write_char (stream, *va_arg (args, char*));
+ break;
+
+ case _C_UCHR:
+ res = objc_write_unsigned_char (stream,
+ *va_arg (args, unsigned char*));
+ break;
+
+ case _C_SHT:
+ res = objc_write_short (stream, *va_arg(args, short*));
+ break;
+
+ case _C_USHT:
+ res = objc_write_unsigned_short (stream,
+ *va_arg(args, unsigned short*));
+ break;
+
+ case _C_INT:
+ case _C_LNG:
+ res = objc_write_int(stream, *va_arg(args, int*));
+ break;
+
+ case _C_UINT:
+ case _C_ULNG:
+ res = objc_write_unsigned_int(stream, *va_arg(args, unsigned int*));
+ break;
+
+ case _C_CHARPTR:
+ {
+ char* str = va_arg(args, char*);
+ res = objc_write_string (stream, str, strlen(str));
+ }
+ break;
+
+ case _C_ATOM:
+ {
+ char* str = va_arg(args, char*);
+ res = objc_write_string_atomic (stream, str, strlen(str));
+ }
+ break;
+
+ case _C_ARY_B:
+ {
+ int len = atoi(c+1);
+ const char* t = c;
+ while (isdigit(*++t));
+ res = objc_write_array (stream, t, len, va_arg(args, void*));
+ t = __objc_skip_type (t);
+ if (*t != _C_ARY_E)
+ __objc_fatal("expected `]', got: %s", t);
+ }
+ break;
+
+ default:
+ fprintf(stderr, "objc_write_type: cannot parse typespec: %s\n", type);
+ abort();
+ }
+ }
+ va_end(args);
+ return res;
+}
+
+
+/*
+** Last arguments specify addresses of values to be read. Expected
+** type is checked against the type actually present on the stream.
+*/
+
+int
+objc_read_types(TypedStream* stream, const char* type, ...)
+{
+ va_list args;
+ const char *c;
+ int res = 0;
+
+ va_start(args, type);
+
+ for (c = type; *c; c = __objc_skip_type(c))
+ {
+ switch(*c) {
+ case _C_ID:
+ res = objc_read_object(stream, va_arg(args, id*));
+ break;
+
+ case _C_CLASS:
+ res = objc_read_class(stream, va_arg(args, Class**));
+ break;
+
+ case _C_SEL:
+ res = objc_read_selector(stream, va_arg(args, SEL*));
+ break;
+
+ case _C_CHR:
+ res = objc_read_char(stream, va_arg(args, char*));
+ break;
+
+ case _C_UCHR:
+ res = objc_read_unsigned_char(stream, va_arg(args, unsigned char*));
+ break;
+
+ case _C_SHT:
+ res = objc_read_short(stream, va_arg(args, short*));
+ break;
+
+ case _C_USHT:
+ res = objc_read_unsigned_short(stream, va_arg(args, unsigned short*));
+ break;
+
+ case _C_INT:
+ case _C_LNG:
+ res = objc_read_int(stream, va_arg(args, int*));
+ break;
+
+ case _C_UINT:
+ case _C_ULNG:
+ res = objc_read_unsigned_int(stream, va_arg(args, unsigned int*));
+ break;
+
+ case _C_CHARPTR:
+ case _C_ATOM:
+ {
+ char** str = va_arg(args, char**);
+ res = objc_read_string (stream, str);
+ }
+ break;
+
+ case _C_ARY_B:
+ {
+ int len = atoi(c+1);
+ const char* t = c;
+ while (isdigit(*++t));
+ res = objc_read_array (stream, t, len, va_arg(args, void*));
+ t = __objc_skip_type (t);
+ if (*t != _C_ARY_E)
+ __objc_fatal("expected `]', got: %s", t);
+ }
+ break;
+
+ default:
+ fprintf(stderr, "objc_read_type: cannot parse typespec: %s\n", type);
+ abort();
+ }
+ }
+ va_end(args);
+ return res;
+}
+
+/*
+** Write an array of COUNT elements of TYPE from the memory address DATA.
+** This is equivalent of objc_write_type (stream, "[N<type>]", data)
+*/
+
+int
+objc_write_array (TypedStream* stream, const char* type,
+ int count, const void* data)
+{
+ int off = objc_sizeof_type(type);
+ const char* where = data;
+
+ while (count-- > 0)
+ {
+ objc_write_type(stream, type, where);
+ where += off;
+ }
+ return 1;
+}
+
+/*
+** Read an array of COUNT elements of TYPE into the memory address
+** DATA. The memory pointed to by data is supposed to be allocated
+** by the callee. This is equivalent of
+** objc_read_type (stream, "[N<type>]", data)
+*/
+
+int
+objc_read_array (TypedStream* stream, const char* type,
+ int count, void* data)
+{
+ int off = objc_sizeof_type(type);
+ char* where = (char*)data;
+
+ while (count-- > 0)
+ {
+ objc_read_type(stream, type, where);
+ where += off;
+ }
+ return 1;
+}
+
+static int
+__objc_fread(FILE* file, char* data, int len)
+{
+ return fread(data, len, 1, file);
+}
+
+static int
+__objc_fwrite(FILE* file, char* data, int len)
+{
+ return fwrite(data, len, 1, file);
+}
+
+static int
+__objc_feof(FILE* file)
+{
+ return feof(file);
+}
+
+static int
+__objc_no_write(FILE* file, char* data, int len)
+{
+ __objc_fatal ("TypedStream not open for writing");
+}
+
+static int
+__objc_no_read(FILE* file, char* data, int len)
+{
+ __objc_fatal ("TypedStream not open for reading");
+}
+
+static int
+__objc_read_typed_stream_signature (TypedStream* stream)
+{
+ char buffer[80];
+ int pos = 0;
+ do
+ (*stream->read)(stream->physical, buffer+pos, 1);
+ while (buffer[pos++] != '\0');
+ sscanf (buffer, "GNU TypedStream %d", &stream->version);
+ if (stream->version != OBJC_TYPED_STREAM_VERSION)
+ __objc_fatal ("cannot handle TypedStream version %d", stream->version);
+ return 1;
+}
+
+static int
+__objc_write_typed_stream_signature (TypedStream* stream)
+{
+ char buffer[80];
+ sprintf(buffer, "GNU TypedStream %d", OBJC_TYPED_STREAM_VERSION);
+ stream->version = OBJC_TYPED_STREAM_VERSION;
+ (*stream->write)(stream->physical, buffer, strlen(buffer)+1);
+ return 1;
+}
+
+static void __objc_finish_write_root_object(struct objc_typed_stream* stream)
+{
+ hash_delete (stream->object_table);
+ stream->object_table = hash_new(64,
+ (hash_func_type)hash_ptr,
+ (compare_func_type)compare_ptrs);
+}
+
+static void __objc_finish_read_root_object(struct objc_typed_stream* stream)
+{
+ node_ptr node;
+ SEL awake_sel = sel_get_uid ("awake");
+
+ /* resolve object forward references */
+ for (node = hash_next (stream->object_refs, NULL); node;
+ node = hash_next (stream->object_refs, node))
+ {
+ struct objc_list* reflist = node->value;
+ const void* key = node->key;
+ id object = hash_value_for_key (stream->object_table, key);
+ while(reflist)
+ {
+ *((id*)reflist->head) = object;
+ reflist = reflist->tail;
+ }
+ list_free (node->value);
+ }
+
+ /* empty object reference table */
+ hash_delete (stream->object_refs);
+ stream->object_refs = hash_new(8, (hash_func_type)hash_ptr,
+ (compare_func_type)compare_ptrs);
+
+ /* call -awake for all objects read */
+ if (awake_sel)
+ {
+ for (node = hash_next (stream->object_table, NULL); node;
+ node = hash_next (stream->object_table, node))
+ {
+ id object = node->value;
+ if (__objc_responds_to (object, awake_sel))
+ (*objc_msg_lookup(object, awake_sel))(object, awake_sel);
+ }
+ }
+
+ /* empty object table */
+ hash_delete (stream->object_table);
+ stream->object_table = hash_new(64,
+ (hash_func_type)hash_ptr,
+ (compare_func_type)compare_ptrs);
+}
+
+/*
+** Open the stream PHYSICAL in MODE
+*/
+
+TypedStream*
+objc_open_typed_stream (FILE* physical, int mode)
+{
+ int fflush(FILE*);
+
+ TypedStream* s = (TypedStream*)__objc_xmalloc(sizeof(TypedStream));
+
+ s->mode = mode;
+ s->physical = physical;
+ s->stream_table = hash_new(64,
+ (hash_func_type)hash_ptr,
+ (compare_func_type)compare_ptrs);
+ s->object_table = hash_new(64,
+ (hash_func_type)hash_ptr,
+ (compare_func_type)compare_ptrs);
+ s->eof = (objc_typed_eof_func)__objc_feof;
+ s->flush = (objc_typed_flush_func)fflush;
+ s->writing_root_p = 0;
+ if (mode == OBJC_READONLY)
+ {
+ s->class_table = hash_new(8, (hash_func_type)hash_string,
+ (compare_func_type)compare_strings);
+ s->object_refs = hash_new(8, (hash_func_type)hash_ptr,
+ (compare_func_type)compare_ptrs);
+ s->read = (objc_typed_read_func)__objc_fread;
+ s->write = (objc_typed_write_func)__objc_no_write;
+ __objc_read_typed_stream_signature (s);
+ }
+ else if (mode == OBJC_WRITEONLY)
+ {
+ s->class_table = 0;
+ s->object_refs = 0;
+ s->read = (objc_typed_read_func)__objc_no_read;
+ s->write = (objc_typed_write_func)__objc_fwrite;
+ __objc_write_typed_stream_signature (s);
+ }
+ else
+ {
+ objc_close_typed_stream (s);
+ return NULL;
+ }
+ s->type = OBJC_FILE_STREAM;
+ return s;
+}
+
+/*
+** Open the file named by FILE_NAME in MODE
+*/
+
+TypedStream*
+objc_open_typed_stream_for_file (const char* file_name, int mode)
+{
+ FILE* file = NULL;
+ TypedStream* s;
+
+ if (mode == OBJC_READONLY)
+ file = fopen (file_name, "r");
+ else
+ file = fopen (file_name, "w");
+
+ if (file)
+ {
+ s = objc_open_typed_stream (file, mode);
+ if (s)
+ s->type |= OBJC_MANAGED_STREAM;
+ return s;
+ }
+ else
+ return NULL;
+}
+
+/*
+** Close STREAM freeing the structure it self. If it was opened with
+** objc_open_typed_stream_for_file, the file will also be closed.
+*/
+
+void
+objc_close_typed_stream (TypedStream* stream)
+{
+ if (stream->mode == OBJC_READONLY)
+ {
+ __objc_finish_read_root_object (stream); /* Just in case... */
+ hash_delete (stream->class_table);
+ hash_delete (stream->object_refs);
+ }
+
+ hash_delete (stream->stream_table);
+ hash_delete (stream->object_table);
+
+ if (stream->type == (OBJC_MANAGED_STREAM | OBJC_FILE_STREAM))
+ fclose ((FILE*)stream->physical);
+
+ free (stream);
+}
+
+BOOL
+objc_end_of_typed_stream (TypedStream* stream)
+{
+ return (*stream->eof)(stream->physical);
+}
+
+void
+objc_flush_typed_stream (TypedStream* stream)
+{
+ (*stream->flush)(stream->physical);
+}
+
+int
+objc_get_stream_class_version (TypedStream* stream, Class* class)
+{
+ if (stream->class_table)
+ return (int) hash_value_for_key (stream->class_table, class->name);
+ else
+ return class_get_version (class);
+}
+
+#endif /* __alpha__ */
diff --git a/gnu/usr.bin/cc/libobjc/class.c b/gnu/usr.bin/cc/libobjc/class.c
new file mode 100644
index 000000000000..c9af0eb1bbf2
--- /dev/null
+++ b/gnu/usr.bin/cc/libobjc/class.c
@@ -0,0 +1,350 @@
+/* GNU Objective C Runtime class related functions
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+Author: Kresten Krab Thorup, Dennis Glatting
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2, or (at your option) any later version.
+
+GNU CC 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 General Public License for more
+ details.
+
+You should have received a copy of the GNU General Public License along with
+ GNU CC; see the file COPYING. If not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* As a special exception, if you link this library with files compiled with
+ GCC to produce an executable, this does not cause the resulting executable
+ to be covered by the GNU General Public License. This exception does not
+ however invalidate any other reasons why the executable file might be
+ covered by the GNU General Public License. */
+
+#include "runtime.h" /* the kitchen sink */
+
+
+/* The table of classname->class. Used for objc_lookup_class and friends */
+static cache_ptr __objc_class_hash = 0;
+
+/* This is a hook which is called by objc_get_class and
+ objc_lookup_class if the runtime is not able to find the class.
+ This may e.g. try to load in the class using dynamic loading */
+Class* (*_objc_lookup_class)(const char* name) = 0;
+
+
+/* True when class links has been resolved */
+BOOL __objc_class_links_resolved = NO;
+
+
+/* Initial number of buckets size of class hash table. */
+#define CLASS_HASH_SIZE 32
+
+void __objc_init_class_tables()
+{
+ /* Allocate the class hash table */
+
+ if(__objc_class_hash)
+ return;
+
+ __objc_class_hash
+ = hash_new (CLASS_HASH_SIZE,
+ (hash_func_type) hash_string,
+ (compare_func_type) compare_strings);
+}
+
+/* This function adds a class to the class hash table, and assigns the
+ class a number, unless it's already known */
+void
+__objc_add_class_to_hash(Class* class)
+{
+ Class* h_class;
+
+ /* make sure the table is there */
+ assert(__objc_class_hash);
+
+ /* make sure it's not a meta class */
+ assert(CLS_ISCLASS(class));
+
+ /* Check to see if the class is already in the hash table. */
+ h_class = hash_value_for_key (__objc_class_hash, class->name);
+ if (!h_class)
+ {
+ /* The class isn't in the hash table. Add the class and assign a class
+ number. */
+ static unsigned int class_number = 1;
+
+ CLS_SETNUMBER(class, class_number);
+ CLS_SETNUMBER(class->class_pointer, class_number);
+
+ ++class_number;
+ hash_add (&__objc_class_hash, class->name, class);
+ }
+}
+
+/* Get the class object for the class named NAME. If NAME does not
+ identify a known class, the hook _objc_lookup_class is called. If
+ this fails, nil is returned */
+Class* objc_lookup_class (const char* name)
+{
+ Class* class;
+
+ /* Make sure the class hash table exists. */
+ assert (__objc_class_hash);
+
+ class = hash_value_for_key (__objc_class_hash, name);
+
+ if (class)
+ return class;
+
+ if (_objc_lookup_class)
+ return (*_objc_lookup_class)(name);
+ else
+ return 0;
+}
+
+/* Get the class object for the class named NAME. If NAME does not
+ identify a known class, the hook _objc_lookup_class is called. If
+ this fails, an error message is issued and the system aborts */
+Class*
+objc_get_class (const char *name)
+{
+ Class* class;
+
+ /* Make sure the class hash table exists. */
+ assert (__objc_class_hash);
+
+ class = hash_value_for_key (__objc_class_hash, name);
+
+ if (class)
+ return class;
+
+ if (_objc_lookup_class)
+ class = (*_objc_lookup_class)(name);
+
+ if(class)
+ return class;
+
+ fprintf(stderr, "objc runtime: cannot find class %s\n", name);
+ abort();
+}
+
+
+/* Resolve super/subclass links for all classes. The only thing we
+ can be sure of is that the class_pointer for class objects point
+ to the right meta class objects */
+void __objc_resolve_class_links()
+{
+ node_ptr node;
+ Class* object_class = objc_get_class ("Object");
+
+ assert(object_class);
+
+ /* Assign subclass links */
+ for (node = hash_next (__objc_class_hash, NULL); node;
+ node = hash_next (__objc_class_hash, node))
+ {
+ Class* class1 = node->value;
+
+ /* Make sure we have what we think we have. */
+ assert (CLS_ISCLASS(class1));
+ assert (CLS_ISMETA(class1->class_pointer));
+
+ /* The class_pointer of all meta classes point to Object's meta class. */
+ class1->class_pointer->class_pointer = object_class->class_pointer;
+
+ if (!(CLS_ISRESOLV(class1)))
+ {
+ CLS_SETRESOLV(class1);
+ CLS_SETRESOLV(class1->class_pointer);
+
+ if(class1->super_class)
+ {
+ Class* a_super_class
+ = objc_get_class ((char *) class1->super_class);
+
+ assert (a_super_class);
+
+ DEBUG_PRINTF ("making class connections for: %s\n",
+ class1->name);
+
+ /* assign subclass links for superclass */
+ class1->sibling_class = a_super_class->subclass_list;
+ a_super_class->subclass_list = class1;
+
+ /* Assign subclass links for meta class of superclass */
+ if (a_super_class->class_pointer)
+ {
+ class1->class_pointer->sibling_class
+ = a_super_class->class_pointer->subclass_list;
+ a_super_class->class_pointer->subclass_list
+ = class1->class_pointer;
+ }
+ }
+ else /* a root class, make its meta object */
+ /* be a subclass of Object */
+ {
+ class1->class_pointer->sibling_class
+ = object_class->subclass_list;
+ object_class->subclass_list = class1->class_pointer;
+ }
+ }
+ }
+
+ /* Assign superclass links */
+ for (node = hash_next (__objc_class_hash, NULL); node;
+ node = hash_next (__objc_class_hash, node))
+ {
+ Class* class1 = node->value;
+ Class* sub_class;
+ for (sub_class = class1->subclass_list; sub_class;
+ sub_class = sub_class->sibling_class)
+ {
+ sub_class->super_class = class1;
+ if(CLS_ISCLASS(sub_class))
+ sub_class->class_pointer->super_class = class1->class_pointer;
+ }
+ }
+}
+
+
+/* This is a incomplete implementation of posing. This function does the
+ bulk of the work but does not initialize the class method caches. That is
+ a run-time specific operation.
+
+I implement posing by hiding SUPER_CLASS, creating new class and meta class
+ structures, initializing it with IMPOSTOR, and changing it such that it is
+ identified as SUPER_CLASS. SUPER_CLASS remains in the hierarchy but is
+ inaccessible by the means. The class hierarchy is then re arranged such
+ that all of the subclasses of SUPER_CLASS now inherit from the new class
+ structures -- except the impostor itself. The only dramatic effect on the
+ application is that subclasses of SUPER_CLASS cannot do a [ ....
+ super_class ] and expect their real super class. */
+Class*
+class_pose_as (Class* impostor, Class* super_class)
+{
+ Class* new_class = (Class*) __objc_xcalloc (1, sizeof (Class));
+ MetaClass* new_meta_class =
+ (MetaClass*) __objc_xmalloc(sizeof (MetaClass));
+ char *new_name = (char *)__objc_xmalloc ((size_t)strlen ((char*)super_class->name) + 12);
+
+ /* We must know the state of the hierachy. Do initial setup if needed */
+ if(!CLS_ISRESOLV(impostor))
+ __objc_resolve_class_links();
+
+ assert (new_class);
+ assert (new_meta_class);
+ assert (new_name);
+
+ assert (CLS_ISCLASS(impostor));
+ assert (CLS_ISCLASS(super_class));
+
+ assert (impostor->instance_size == super_class->instance_size);
+
+ /* Create the impostor class. */
+ new_class->class_pointer = new_meta_class;
+ new_class->super_class = super_class;
+ new_class->name = super_class->name;
+ new_class->version = super_class->version;
+ new_class->info = super_class->info;
+ new_class->instance_size = super_class->instance_size;
+ new_class->ivars = super_class->ivars;
+ new_class->methods = impostor->methods;
+ new_class->dtable = impostor->dtable;
+
+ /* Create the impostor meta class. */
+ new_meta_class->class_pointer = super_class->class_pointer->class_pointer;
+ new_meta_class->super_class = super_class->class_pointer->super_class;
+ new_meta_class->name = super_class->class_pointer->name;
+ new_meta_class->version = super_class->class_pointer->version;
+ new_meta_class->info = super_class->class_pointer->info;
+ new_meta_class->instance_size = super_class->class_pointer->instance_size;
+ new_meta_class->ivars = super_class->class_pointer->ivars;
+ new_meta_class->methods = impostor->class_pointer->methods;
+ new_meta_class->dtable = impostor->class_pointer->dtable;
+
+ /* Now change super/subclass links of all related classes. This is rather
+ complex, since we have both super_class link, and subclass_list for the
+ involved classes. */
+ {
+ Class* *classpp;
+ MetaClass* *metaclasspp;
+
+ /* Remove impostor from subclass list of super_class */
+ for (classpp = &(super_class->subclass_list);
+ *classpp;
+ classpp = &((*classpp)->sibling_class))
+ {
+ if (*classpp == impostor)
+ *classpp = (*classpp)->sibling_class;
+ if (*classpp == 0)
+ break;
+ }
+
+ /* Do the same for the meta classes */
+
+ for (metaclasspp = &(super_class->class_pointer->subclass_list);
+ *metaclasspp;
+ metaclasspp = &((*metaclasspp)->sibling_class))
+ {
+ if (*metaclasspp == impostor->class_pointer)
+ *metaclasspp = (*metaclasspp)->sibling_class;
+ if (*metaclasspp == 0)
+ break;
+ }
+
+ /* From the loop above, classpp now points to the sibling_class entry */
+ /* of the last element in the list of subclasses for super_class */
+
+ /* Append the subclass list of impostor to the subclass list of */
+ /* superclass, and excange those two and set subclass of */
+ /* super_class to be impostor only */
+
+ *classpp = impostor->subclass_list;
+ new_class->subclass_list = super_class->subclass_list;
+ super_class->subclass_list = new_class;
+ new_class->sibling_class = 0;
+
+ /* Do the same thing for the meta classes */
+ *metaclasspp = impostor->class_pointer->subclass_list;
+ new_meta_class->subclass_list = super_class->class_pointer->subclass_list;
+ super_class->class_pointer->subclass_list = new_meta_class;
+ new_meta_class->sibling_class = 0;
+
+ /* Update superclass links for all subclasses of new_class */
+ for (classpp = &(new_class->subclass_list); *classpp;
+ classpp = &((*classpp)->sibling_class))
+ (*classpp)->super_class = new_class;
+
+ for (metaclasspp = &(new_meta_class->subclass_list); *metaclasspp;
+ metaclasspp = &((*metaclasspp)->sibling_class))
+ (*metaclasspp)->super_class = new_meta_class;
+
+ }
+
+ /* Delete the class from the hash table, change its name so that it can no
+ longer be found, then place it back into the hash table using its new
+ name.
+
+ Don't worry about the class number. It is already assigned.
+ memory is lost with the hash key.) */
+ hash_remove (__objc_class_hash, super_class->name);
+ sprintf (new_name, "%s*", super_class->name);
+ super_class->name = new_name;
+ super_class->class_pointer->name = new_name;
+ hash_add (&__objc_class_hash, super_class->name, super_class);
+
+ /* Place the impostor class in class hash table and assign it a class
+ number. */
+ __objc_add_class_to_hash (new_class);
+
+ /* Now update dispatch tables for new_class and it's subclasses */
+ __objc_update_dispatch_table_for_class ((Class*) new_meta_class);
+ __objc_update_dispatch_table_for_class (new_class);
+
+ return new_class;
+}
+
diff --git a/gnu/usr.bin/cc/libobjc/gstdarg.h b/gnu/usr.bin/cc/libobjc/gstdarg.h
new file mode 100644
index 000000000000..dfa734ba39c6
--- /dev/null
+++ b/gnu/usr.bin/cc/libobjc/gstdarg.h
@@ -0,0 +1,156 @@
+/* stdarg.h for GNU.
+ Note that the type used in va_arg is supposed to match the
+ actual type **after default promotions**.
+ Thus, va_arg (..., short) is not valid. */
+
+#ifndef _STDARG_H
+#ifndef _ANSI_STDARG_H_
+#ifndef __need___va_list
+#define _STDARG_H
+#define _ANSI_STDARG_H_
+#endif /* not __need___va_list */
+#undef __need___va_list
+
+#ifndef __GNUC__
+/* Use the system's macros with the system's compiler.
+ This is relevant only when building GCC with some other compiler. */
+#include <stdarg.h>
+#else
+#ifdef __clipper__
+#include <va-clipper.h>
+#else
+#ifdef __m88k__
+#include <va-m88k.h>
+#else
+#ifdef __i860__
+#include <va-i860.h>
+#else
+#ifdef __hppa__
+#include <va-pa.h>
+#else
+#ifdef __mips__
+#include <va-mips.h>
+#else
+#ifdef __sparc__
+#include <va-sparc.h>
+#else
+#ifdef __i960__
+#include <va-i960.h>
+#else
+#ifdef __alpha__
+#include <va-alpha.h>
+#else
+
+/* Define __gnuc_va_list. */
+
+#ifndef __GNUC_VA_LIST
+#define __GNUC_VA_LIST
+#if defined(__svr4__) || defined(_AIX) || defined(_M_UNIX)
+typedef char *__gnuc_va_list;
+#else
+typedef void *__gnuc_va_list;
+#endif
+#endif
+
+/* Define the standard macros for the user,
+ if this invocation was from the user program. */
+#ifdef _STDARG_H
+
+/* Amount of space required in an argument list for an arg of type TYPE.
+ TYPE may alternatively be an expression whose type is used. */
+
+#define __va_rounded_size(TYPE) \
+ (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))
+
+#define va_start(AP, LASTARG) \
+ (AP = ((__gnuc_va_list) __builtin_next_arg ()))
+
+#undef va_end
+void va_end (__gnuc_va_list); /* Defined in libgcc.a */
+#define va_end(AP)
+
+/* We cast to void * and then to TYPE * because this avoids
+ a warning about increasing the alignment requirement. */
+
+#if defined (__arm__) || defined (__i386__) || defined (__ns32000__) || defined (__vax__)
+/* This is for little-endian machines; small args are padded upward. */
+#define va_arg(AP, TYPE) \
+ (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)), \
+ *((TYPE *) (void *) ((char *) (AP) - __va_rounded_size (TYPE))))
+#else /* big-endian */
+/* This is for big-endian machines; small args are padded downward. */
+#define va_arg(AP, TYPE) \
+ (AP = (__gnuc_va_list) ((char *) (AP) + __va_rounded_size (TYPE)), \
+ *((TYPE *) (void *) ((char *) (AP) - ((sizeof (TYPE) < 4 \
+ ? sizeof (TYPE) \
+ : __va_rounded_size (TYPE))))))
+#endif /* big-endian */
+#endif /* _STDARG_H */
+
+#endif /* not alpha */
+#endif /* not i960 */
+#endif /* not sparc */
+#endif /* not mips */
+#endif /* not hppa */
+#endif /* not i860 */
+#endif /* not m88k */
+#endif /* not clipper */
+
+#ifdef _STDARG_H
+/* Define va_list, if desired, from __gnuc_va_list. */
+/* We deliberately do not define va_list when called from
+ stdio.h, because ANSI C says that stdio.h is not supposed to define
+ va_list. stdio.h needs to have access to that data type,
+ but must not use that name. It should use the name __gnuc_va_list,
+ which is safe because it is reserved for the implementation. */
+
+#ifdef _HIDDEN_VA_LIST /* On OSF1, this means varargs.h is "half-loaded". */
+#undef _VA_LIST
+#endif
+
+#ifdef _BSD_VA_LIST
+#undef _BSD_VA_LIST
+#endif
+
+#ifdef __svr4__
+/* SVR4.2 uses _VA_LIST for an internal alias for va_list,
+ so we must avoid testing it and setting it here.
+ SVR4 uses _VA_LIST as a flag in stdarg.h, but we should
+ have no conflict with that. */
+#ifndef _VA_LIST_
+#define _VA_LIST_
+#ifdef __i860__
+#ifndef _VA_LIST
+#define _VA_LIST va_list
+#endif
+#endif /* __i860__ */
+typedef __gnuc_va_list va_list;
+#endif /* _VA_LIST_ */
+#else /* not __svr4__ */
+
+/* The macro _VA_LIST_ is the same thing used by this file in Ultrix.
+ But on BSD NET2 we must not test or define or undef it.
+ (Note that the comments in NET 2's ansi.h
+ are incorrect for _VA_LIST_--see stdio.h!) */
+#if !defined (_VA_LIST_) || defined (__BSD_NET2__) || defined (____386BSD____)
+/* The macro _VA_LIST is used in SCO Unix 3.2. */
+#ifndef _VA_LIST
+/* The macro _VA_LIST_T_H is used in the Bull dpx2 */
+#ifndef _VA_LIST_T_H
+#define _VA_LIST_T_H
+#if !(defined (__BSD_NET2__) || defined (____386BSD____))
+#define _VA_LIST_
+#endif
+#define _VA_LIST
+typedef __gnuc_va_list va_list;
+#endif /* not _VA_LIST_T_H */
+#endif /* not _VA_LIST */
+#endif /* not _VA_LIST_ */
+
+#endif /* not __svr4__ */
+
+#endif /* _STDARG_H */
+
+#endif /* __GNUC__ */
+#endif /* not _ANSI_STDARG_H_ */
+#endif /* not _STDARG_H */
diff --git a/gnu/usr.bin/cc/libobjc/hash.c b/gnu/usr.bin/cc/libobjc/hash.c
new file mode 100644
index 000000000000..2226a2630b16
--- /dev/null
+++ b/gnu/usr.bin/cc/libobjc/hash.c
@@ -0,0 +1,250 @@
+/* Hash tables for Objective C internal structures
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* As a special exception, if you link this library with files
+ compiled with GCC to produce an executable, this does not cause
+ the resulting executable to be covered by the GNU General Public License.
+ This exception does not however invalidate any other reasons why
+ the executable file might be covered by the GNU General Public License. */
+
+#include "assert.h"
+
+#include "objc/hash.h"
+#include "objc/objc.h"
+
+#include "runtime.h" /* for DEBUG_PRINTF */
+
+/* These two macros determine when a hash table is full and
+ by how much it should be expanded respectively.
+
+ These equations are percentages. */
+#define FULLNESS(cache) \
+ ((((cache)->size * 75) / 100) <= (cache)->used)
+#define EXPANSION(cache) \
+ ((cache)->size * 2)
+
+cache_ptr
+hash_new (unsigned int size, hash_func_type hash_func,
+ compare_func_type compare_func)
+{
+ cache_ptr cache;
+
+ /* Pass me a value greater than 0 and a power of 2. */
+ assert (size);
+ assert (!(size & (size - 1)));
+
+ /* Allocate the cache structure. calloc insures
+ its initialization for default values. */
+ cache = (cache_ptr) __objc_xcalloc (1, sizeof (struct cache));
+ assert (cache);
+
+ /* Allocate the array of buckets for the cache.
+ calloc initializes all of the pointers to NULL. */
+ cache->node_table
+ = (node_ptr *) __objc_xcalloc (size, sizeof (node_ptr));
+ assert (cache->node_table);
+
+ cache->size = size;
+
+ /* This should work for all processor architectures? */
+ cache->mask = (size - 1);
+
+ /* Store the hashing function so that codes can be computed. */
+ cache->hash_func = hash_func;
+
+ /* Store the function that compares hash keys to
+ determine if they are equal. */
+ cache->compare_func = compare_func;
+
+ return cache;
+}
+
+
+void
+hash_delete (cache_ptr cache)
+{
+ node_ptr node;
+
+
+ /* Purge all key/value pairs from the table. */
+ while ((node = hash_next (cache, NULL)))
+ hash_remove (cache, node->key);
+
+ /* Release the array of nodes and the cache itself. */
+ free (cache->node_table);
+ free (cache);
+}
+
+
+void
+hash_add (cache_ptr *cachep, const void *key, void *value)
+{
+ size_t indx = (*(*cachep)->hash_func)(*cachep, key);
+ node_ptr node = (node_ptr) __objc_xcalloc (1, sizeof (struct cache_node));
+
+
+ assert (node);
+
+ /* Initialize the new node. */
+ node->key = key;
+ node->value = value;
+ node->next = (*cachep)->node_table[indx];
+
+ /* Debugging.
+ Check the list for another key. */
+#ifdef DEBUG
+ { node_ptr node1 = (*cachep)->node_table[indx];
+
+ while (node1) {
+
+ assert (node1->key != key);
+ node1 = node1->next;
+ }
+ }
+#endif
+
+ /* Install the node as the first element on the list. */
+ (*cachep)->node_table[indx] = node;
+
+ /* Bump the number of entries in the cache. */
+ ++(*cachep)->used;
+
+ /* Check the hash table's fullness. We're going
+ to expand if it is above the fullness level. */
+ if (FULLNESS (*cachep)) {
+
+ /* The hash table has reached its fullness level. Time to
+ expand it.
+
+ I'm using a slow method here but is built on other
+ primitive functions thereby increasing its
+ correctness. */
+ node_ptr node1 = NULL;
+ cache_ptr new = hash_new (EXPANSION (*cachep),
+ (*cachep)->hash_func,
+ (*cachep)->compare_func);
+
+ DEBUG_PRINTF ("Expanding cache %#x from %d to %d\n",
+ *cachep, (*cachep)->size, new->size);
+
+ /* Copy the nodes from the first hash table to the new one. */
+ while ((node1 = hash_next (*cachep, node1)))
+ hash_add (&new, node1->key, node1->value);
+
+ /* Trash the old cache. */
+ hash_delete (*cachep);
+
+ /* Return a pointer to the new hash table. */
+ *cachep = new;
+ }
+}
+
+
+void
+hash_remove (cache_ptr cache, const void *key)
+{
+ size_t indx = (*cache->hash_func)(cache, key);
+ node_ptr node = cache->node_table[indx];
+
+
+ /* We assume there is an entry in the table. Error if it is not. */
+ assert (node);
+
+ /* Special case. First element is the key/value pair to be removed. */
+ if ((*cache->compare_func)(node->key, key)) {
+ cache->node_table[indx] = node->next;
+ free (node);
+ } else {
+
+ /* Otherwise, find the hash entry. */
+ node_ptr prev = node;
+ BOOL removed = NO;
+
+ do {
+
+ if ((*cache->compare_func)(node->key, key)) {
+ prev->next = node->next, removed = YES;
+ free (node);
+ } else
+ prev = node, node = node->next;
+ } while (!removed && node);
+ assert (removed);
+ }
+
+ /* Decrement the number of entries in the hash table. */
+ --cache->used;
+}
+
+
+node_ptr
+hash_next (cache_ptr cache, node_ptr node)
+{
+ /* If the scan is being started then reset the last node
+ visitied pointer and bucket index. */
+ if (!node)
+ cache->last_bucket = 0;
+
+ /* If there is a node visited last then check for another
+ entry in the same bucket; Otherwise step to the next bucket. */
+ if (node) {
+ if (node->next)
+ /* There is a node which follows the last node
+ returned. Step to that node and retun it. */
+ return node->next;
+ else
+ ++cache->last_bucket;
+ }
+
+ /* If the list isn't exhausted then search the buckets for
+ other nodes. */
+ if (cache->last_bucket < cache->size) {
+ /* Scan the remainder of the buckets looking for an entry
+ at the head of the list. Return the first item found. */
+ while (cache->last_bucket < cache->size)
+ if (cache->node_table[cache->last_bucket])
+ return cache->node_table[cache->last_bucket];
+ else
+ ++cache->last_bucket;
+
+ /* No further nodes were found in the hash table. */
+ return NULL;
+ } else
+ return NULL;
+}
+
+
+/* Given KEY, return corresponding value for it in CACHE.
+ Return NULL if the KEY is not recorded. */
+
+void *
+hash_value_for_key (cache_ptr cache, const void *key)
+{
+ node_ptr node = cache->node_table[(*cache->hash_func)(cache, key)];
+ void *retval = NULL;
+
+ if (node)
+ do {
+ if ((*cache->compare_func)(node->key, key))
+ retval = node->value;
+ else
+ node = node->next;
+ } while (!retval && node);
+
+ return retval;
+}
diff --git a/gnu/usr.bin/cc/libobjc/hash.h b/gnu/usr.bin/cc/libobjc/hash.h
new file mode 100644
index 000000000000..e054e7d03aa9
--- /dev/null
+++ b/gnu/usr.bin/cc/libobjc/hash.h
@@ -0,0 +1,200 @@
+/* Hash tables for Objective C method dispatch.
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* As a special exception, if you link this library with files
+ compiled with GCC to produce an executable, this does not cause
+ the resulting executable to be covered by the GNU General Public License.
+ This exception does not however invalidate any other reasons why
+ the executable file might be covered by the GNU General Public License. */
+
+
+#ifndef __hash_INCLUDE_GNU
+#define __hash_INCLUDE_GNU
+
+#ifdef IN_GCC
+#include "gstddef.h"
+#else
+#include "stddef.h"
+#endif
+
+/*
+ * This data structure is used to hold items
+ * stored in a hash table. Each node holds
+ * a key/value pair.
+ *
+ * Items in the cache are really of type void *.
+ */
+typedef struct cache_node
+{
+ struct cache_node *next; /* Pointer to next entry on the list.
+ NULL indicates end of list. */
+ const void *key; /* Key used to locate the value. Used
+ to locate value when more than one
+ key computes the same hash
+ value. */
+ void *value; /* Value stored for the key. */
+} *node_ptr;
+
+
+/*
+ * This data type is the function that computes a hash code given a key.
+ * Therefore, the key can be a pointer to anything and the function specific
+ * to the key type.
+ *
+ * Unfortunately there is a mutual data structure reference problem with this
+ * typedef. Therefore, to remove compiler warnings the functions passed to
+ * hash_new will have to be casted to this type.
+ */
+typedef unsigned int (*hash_func_type)(void *, const void *);
+
+/*
+ * This data type is the function that compares two hash keys and returns an
+ * integer greater than, equal to, or less than 0, according as the first
+ * parameter is lexico-graphically greater than, equal to, or less than the
+ * second.
+ */
+
+typedef int (*compare_func_type)(const void *, const void *);
+
+
+/*
+ * This data structure is the cache.
+ *
+ * It must be passed to all of the hashing routines
+ * (except for new).
+ */
+typedef struct cache
+{
+ /* Variables used to implement the hash itself. */
+ node_ptr *node_table; /* Pointer to an array of hash nodes. */
+ /* Variables used to track the size of the hash table so to determine
+ when to resize it. */
+ unsigned int size; /* Number of buckets allocated for the hash table
+ (number of array entries allocated for
+ "node_table"). Must be a power of two. */
+ unsigned int used; /* Current number of entries in the hash table. */
+ unsigned int mask; /* Precomputed mask. */
+
+ /* Variables used to implement indexing through the hash table. */
+
+ unsigned int last_bucket; /* Tracks which entry in the array where
+ the last value was returned. */
+ /* Function used to compute a hash code given a key.
+ This function is specified when the hash table is created. */
+ hash_func_type hash_func;
+ /* Function used to compare two hash keys to see if they are equal. */
+ compare_func_type compare_func;
+} *cache_ptr;
+
+
+/* Two important hash tables. */
+extern cache_ptr module_hash_table, class_hash_table;
+
+/* Allocate and initialize a hash table. */
+
+cache_ptr hash_new (unsigned int size,
+ hash_func_type hash_func,
+ compare_func_type compare_func);
+
+/* Deallocate all of the hash nodes and the cache itself. */
+
+void hash_delete (cache_ptr cache);
+
+/* Add the key/value pair to the hash table. If the
+ hash table reaches a level of fullnes then it will be resized.
+
+ assert if the key is already in the hash. */
+
+void hash_add (cache_ptr *cachep, const void *key, void *value);
+
+/* Remove the key/value pair from the hash table.
+ assert if the key isn't in the table. */
+
+void hash_remove (cache_ptr cache, const void *key);
+
+/* Used to index through the hash table. Start with NULL
+ to get the first entry.
+
+ Successive calls pass the value returned previously.
+ ** Don't modify the hash during this operation ***
+
+ Cache nodes are returned such that key or value can
+ be extracted. */
+
+node_ptr hash_next (cache_ptr cache, node_ptr node);
+
+/* Used to return a value from a hash table using a given key. */
+
+void *hash_value_for_key (cache_ptr cache, const void *key);
+
+
+/************************************************
+
+ Useful hashing functions.
+
+ Declared inline for your pleasure.
+
+************************************************/
+
+/* Calculate a hash code by performing some
+ manipulation of the key pointer. (Use the lowest bits
+ except for those likely to be 0 due to alignment.) */
+
+static inline unsigned int
+hash_ptr (cache_ptr cache, const void *key)
+{
+ return ((size_t)key / sizeof (void *)) & cache->mask;
+}
+
+
+/* Calculate a hash code by iterating over a NULL
+ terminate string. */
+static inline unsigned int
+hash_string (cache_ptr cache, const void *key)
+{
+ unsigned int ret = 0;
+ unsigned int ctr = 0;
+
+
+ while (*(char*)key) {
+ ret ^= *(char*)key++ << ctr;
+ ctr = (ctr + 1) % sizeof (void *);
+ }
+
+ return ret & cache->mask;
+}
+
+
+/* Compare two pointers for equality. */
+static inline int
+compare_ptrs (const void *k1, const void *k2)
+{
+ return !(k1 - k2);
+}
+
+
+/* Compare two strings. */
+static inline int
+compare_strings (const void *k1, const void *k2)
+{
+ return !strcmp (k1, k2);
+}
+
+
+#endif /* not __hash_INCLUDE_GNU */
diff --git a/gnu/usr.bin/cc/libobjc/init.c b/gnu/usr.bin/cc/libobjc/init.c
new file mode 100644
index 000000000000..220d7d23e648
--- /dev/null
+++ b/gnu/usr.bin/cc/libobjc/init.c
@@ -0,0 +1,275 @@
+/* GNU Objective C Runtime initialization
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+Author: Kresten Krab Thorup
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2, or (at your option) any later version.
+
+GNU CC 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 General Public License for more
+ details.
+
+You should have received a copy of the GNU General Public License along with
+ GNU CC; see the file COPYING. If not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* As a special exception, if you link this library with files compiled with
+ GCC to produce an executable, this does not cause the resulting executable
+ to be covered by the GNU General Public License. This exception does not
+ however invalidate any other reasons why the executable file might be
+ covered by the GNU General Public License. */
+
+#include "runtime.h"
+
+/* The version number of this runtime. This must match the number
+ defined in gcc (objc-act.c) */
+#define OBJC_VERSION 5
+#define PROTOCOL_VERSION 2
+
+/* This list contains all modules currently loaded into the runtime */
+static struct objc_list* __objc_module_list = 0;
+
+/* This list contains all proto_list's not yet assigned class links */
+static struct objc_list* unclaimed_proto_list = 0;
+
+/* Check compiler vs runtime version */
+static void init_check_module_version(Module_t);
+
+/* Assign isa links to protos */
+static void __objc_init_protocols (struct objc_protocol_list* protos);
+
+/* Add protocol to class */
+static void __objc_class_add_protocols (Class*, struct objc_protocol_list*);
+
+/* Is all categories/classes resolved? */
+BOOL __objc_dangling_categories = NO;
+
+/* This function is called by constructor functions generated for each
+ module compiled. (_GLOBAL_$I$...) The purpose of this function is to
+ gather the module pointers so that they may be processed by the
+ initialization routines as soon as possible */
+
+void
+__objc_exec_class (Module_t module)
+{
+ /* Has we processed any constructors previously? This flag used to
+ indicate that some global data structures need to be built. */
+ static BOOL previous_constructors = 0;
+
+ static struct objc_list* unclaimed_categories = 0;
+
+ /* The symbol table (defined in objc.h) generated by gcc */
+ Symtab_t symtab = module->symtab;
+
+ /* Entry used to traverse hash lists */
+ struct objc_list** cell;
+
+ /* The table of selector references for this module */
+ SEL *selectors = symtab->refs;
+
+ /* dummy counter */
+ int i;
+
+ DEBUG_PRINTF ("received module: %s\n", module->name);
+ /* check gcc version */
+ init_check_module_version(module);
+
+ /* On the first call of this routine, initialize some data structures. */
+ if (!previous_constructors)
+ {
+ __objc_init_selector_tables();
+ __objc_init_class_tables();
+ __objc_init_dispatch_tables();
+ previous_constructors = 1;
+ }
+
+ /* Save the module pointer for later processing. (not currently used) */
+ __objc_module_list = list_cons(module, __objc_module_list);
+
+ /* Parse the classes in the load module and gather selector information. */
+ DEBUG_PRINTF ("gathering selectors from module: %s\n", module->name);
+ for (i = 0; i < symtab->cls_def_cnt; ++i)
+ {
+ Class* class = (Class*) symtab->defs[i];
+
+ /* Make sure we have what we think. */
+ assert (CLS_ISCLASS(class));
+ assert (CLS_ISMETA(class->class_pointer));
+ DEBUG_PRINTF ("phase 1, processing class: %s\n", class->name);
+
+ /* Store the class in the class table and assign class numbers. */
+ __objc_add_class_to_hash (class);
+
+ /* Register all of the selectors in the class and meta class. */
+ __objc_register_selectors_from_class (class);
+ __objc_register_selectors_from_class ((Class*) class->class_pointer);
+
+ /* Install the fake dispatch tables */
+ __objc_install_premature_dtable(class);
+ __objc_install_premature_dtable(class->class_pointer);
+
+ if (class->protocols)
+ __objc_init_protocols (class->protocols);
+ }
+
+ /* Replace referenced selectors from names to SEL's. */
+ if (selectors)
+ {
+ for (i = 0; selectors[i]; ++i)
+ selectors[i] = sel_register_name ((const char *) selectors[i]);
+ }
+
+ /* Process category information from the module. */
+ for (i = 0; i < symtab->cat_def_cnt; ++i)
+ {
+ Category_t category = symtab->defs[i + symtab->cls_def_cnt];
+ Class* class = objc_lookup_class (category->class_name);
+
+ /* If the class for the category exists then append its methods. */
+ if (class)
+ {
+
+ DEBUG_PRINTF ("processing categories from (module,object): %s, %s\n",
+ module->name,
+ class->name);
+
+ /* Do instance methods. */
+ if (category->instance_methods)
+ class_add_method_list (class, category->instance_methods);
+
+ /* Do class methods. */
+ if (category->class_methods)
+ class_add_method_list ((Class*) class->class_pointer,
+ category->class_methods);
+
+ if (category->protocols)
+ {
+ __objc_init_protocols (category->protocols);
+ __objc_class_add_protocols (class, category->protocols);
+ }
+
+ }
+ else
+ {
+ /* The object to which the category methods belong can't be found.
+ Save the information. */
+ unclaimed_categories = list_cons(category, unclaimed_categories);
+ }
+ }
+
+ /* Scan the unclaimed category hash. Attempt to attach any unclaimed
+ categories to objects. */
+ for (cell = &unclaimed_categories;
+ *cell;
+ *cell && ((cell = &(*cell)->tail)))
+ {
+ Category_t category = (*cell)->head;
+ Class* class = objc_lookup_class (category->class_name);
+
+ if (class)
+ {
+ DEBUG_PRINTF ("attaching stored categories to object: %s\n",
+ class->name);
+
+ list_remove_head (cell);
+
+ if (category->instance_methods)
+ class_add_method_list (class, category->instance_methods);
+
+ if (category->class_methods)
+ class_add_method_list ((Class*) class->class_pointer,
+ category->class_methods);
+
+ if (category->protocols)
+ {
+ __objc_init_protocols (category->protocols);
+ __objc_class_add_protocols (class, category->protocols);
+ }
+
+ }
+ }
+
+ if (unclaimed_proto_list && objc_lookup_class ("Protocol"))
+ {
+ list_mapcar (unclaimed_proto_list,(void(*)(void*))__objc_init_protocols);
+ list_free (unclaimed_proto_list);
+ unclaimed_proto_list = 0;
+ }
+
+}
+
+/* Sanity check the version of gcc used to compile `module'*/
+static void init_check_module_version(Module_t module)
+{
+ if ((module->version != OBJC_VERSION) || (module->size != sizeof (Module)))
+ {
+ fprintf (stderr, "Module %s version %d doesn't match runtime %d\n",
+ module->name, module->version, OBJC_VERSION);
+ if(module->version > OBJC_VERSION)
+ fprintf (stderr, "Runtime (libobjc.a) is out of date\n");
+ else if (module->version < OBJC_VERSION)
+ fprintf (stderr, "Compiler (gcc) is out of date\n");
+ else
+ fprintf (stderr, "Objective C internal error -- bad Module size\n");
+ abort ();
+ }
+}
+
+static void
+__objc_init_protocols (struct objc_protocol_list* protos)
+{
+ int i;
+ static Class* proto_class = 0;
+
+ if (! protos)
+ return;
+
+ if (!proto_class)
+ proto_class = objc_lookup_class("Protocol");
+
+ if (!proto_class)
+ {
+ unclaimed_proto_list = list_cons (protos, unclaimed_proto_list);
+ return;
+ }
+
+ assert (protos->next == 0); /* only single ones allowed */
+
+ for(i = 0; i < protos->count; i++)
+ {
+ struct objc_protocol* aProto = protos->list[i];
+ if (((size_t)aProto->class_pointer) == PROTOCOL_VERSION)
+ {
+ /* assign class pointer */
+ aProto->class_pointer = proto_class;
+
+ /* init super protocols */
+ __objc_init_protocols (aProto->protocol_list);
+ }
+ else if (protos->list[i]->class_pointer != proto_class)
+ {
+ fprintf (stderr,
+ "Version %d doesn't match runtime protocol version %d\n",
+ ((size_t)protos->list[i]->class_pointer),
+ PROTOCOL_VERSION);
+ abort ();
+ }
+ }
+}
+
+static void __objc_class_add_protocols (Class* class,
+ struct objc_protocol_list* protos)
+{
+ /* Well... */
+ if (! protos)
+ return;
+
+ /* Add it... */
+ protos->next = class->protocols;
+ class->protocols = protos;
+}
diff --git a/gnu/usr.bin/cc/libobjc/list.h b/gnu/usr.bin/cc/libobjc/list.h
new file mode 100644
index 000000000000..37d7caed15b9
--- /dev/null
+++ b/gnu/usr.bin/cc/libobjc/list.h
@@ -0,0 +1,145 @@
+/* Generic single linked list to keep various information
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+Author: Kresten Krab Thorup
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2, or (at your option) any later version.
+
+GNU CC 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 General Public License for more
+ details.
+
+You should have received a copy of the GNU General Public License along with
+ GNU CC; see the file COPYING. If not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* As a special exception, if you link this library with files compiled with
+ GCC to produce an executable, this does not cause the resulting executable
+ to be covered by the GNU General Public License. This exception does not
+ however invalidate any other reasons why the executable file might be
+ covered by the GNU General Public License. */
+
+void * __objc_xrealloc (void *optr, size_t size);
+void * __objc_xmalloc (size_t size);
+
+struct objc_list {
+ void *head;
+ struct objc_list *tail;
+};
+
+/* Return a cons cell produced from (head . tail) */
+
+static inline struct objc_list*
+list_cons(void* head, struct objc_list* tail)
+{
+ struct objc_list* cell;
+
+ cell = (struct objc_list*)__objc_xmalloc(sizeof(struct objc_list));
+ cell->head = head;
+ cell->tail = tail;
+ return cell;
+}
+
+/* Return the length of a list, list_length(NULL) returns zero */
+
+static inline int
+list_length(struct objc_list* list)
+{
+ int i = 0;
+ while(list)
+ {
+ i += 1;
+ list = list->tail;
+ }
+ return i;
+}
+
+/* Return the Nth element of LIST, where N count from zero. If N
+ larger than the list length, NULL is returned */
+
+static inline void*
+list_nth(int index, struct objc_list* list)
+{
+ while(index-- != 0)
+ {
+ if(list->tail)
+ list = list->tail;
+ else
+ return 0;
+ }
+ return list->head;
+}
+
+/* Remove the element at the head by replacing it by its successor */
+
+static inline void
+list_remove_head(struct objc_list** list)
+{
+ if ((*list)->tail)
+ {
+ struct objc_list* tail = (*list)->tail; /* fetch next */
+ *(*list) = *tail; /* copy next to list head */
+ free(tail); /* free next */
+ }
+ else /* only one element in list */
+ {
+ free (*list);
+ (*list) = 0;
+ }
+}
+
+
+/* Remove the element with `car' set to ELEMENT */
+
+static inline void
+list_remove_elem(struct objc_list** list, void* elem)
+{
+ while (*list) {
+ if ((*list)->head == elem)
+ list_remove_head(list);
+ list = &((*list)->tail);
+ }
+}
+
+/* Map FUNCTION over all elements in LIST */
+
+static inline void
+list_mapcar(struct objc_list* list, void(*function)(void*))
+{
+ while(list)
+ {
+ (*function)(list->head);
+ list = list->tail;
+ }
+}
+
+/* Return element that has ELEM as car */
+
+static inline struct objc_list**
+list_find(struct objc_list** list, void* elem)
+{
+ while(*list)
+ {
+ if ((*list)->head == elem)
+ return list;
+ list = &((*list)->tail);
+ }
+ return NULL;
+}
+
+/* Free list (backwards recursive) */
+
+static void
+list_free(struct objc_list* list)
+{
+ if(list)
+ {
+ list_free(list->tail);
+ free(list);
+ }
+}
diff --git a/gnu/usr.bin/cc/libobjc/misc.c b/gnu/usr.bin/cc/libobjc/misc.c
new file mode 100644
index 000000000000..6b6b34298225
--- /dev/null
+++ b/gnu/usr.bin/cc/libobjc/misc.c
@@ -0,0 +1,72 @@
+/* GNU Objective C Runtime Miscellanious
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+Author: Kresten Krab Thorup
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2, or (at your option) any later version.
+
+GNU CC 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 General Public License for more
+ details.
+
+You should have received a copy of the GNU General Public License along with
+ GNU CC; see the file COPYING. If not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* As a special exception, if you link this library with files compiled with
+ GCC to produce an executable, this does not cause the resulting executable
+ to be covered by the GNU General Public License. This exception does not
+ however invalidate any other reasons why the executable file might be
+ covered by the GNU General Public License. */
+
+#include "runtime.h"
+
+void objc_error(id object, const char* fmt, va_list);
+
+void (*_objc_error)(id, const char*, va_list) = objc_error;
+
+void
+objc_error(id object, const char* fmt, va_list ap)
+{
+ vfprintf (stderr, fmt, ap);
+ abort ();
+}
+
+volatile void
+objc_fatal(const char* msg)
+{
+ write(2, msg, (size_t)strlen((char*)msg));
+ abort();
+}
+
+void*
+__objc_xmalloc(size_t size)
+{
+ void* res = (void*) malloc(size);
+ if(!res)
+ objc_fatal("Virtual memory exhausted\n");
+ return res;
+}
+
+void*
+__objc_xrealloc(void* mem, size_t size)
+{
+ void* res = (void*) realloc(mem, size);
+ if(!res)
+ objc_fatal("Virtual memory exhausted\n");
+ return res;
+}
+
+void*
+__objc_xcalloc(size_t nelem, size_t size)
+{
+ void* res = (void*)calloc(nelem, size);
+ if(!res)
+ objc_fatal("Virtual memory exhausted\n");
+ return res;
+}
diff --git a/gnu/usr.bin/cc/libobjc/objc-api.h b/gnu/usr.bin/cc/libobjc/objc-api.h
new file mode 100644
index 000000000000..1a5756d6d14c
--- /dev/null
+++ b/gnu/usr.bin/cc/libobjc/objc-api.h
@@ -0,0 +1,450 @@
+/* GNU Objective-C Runtime API.
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU CC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* As a special exception, if you link this library with files compiled
+ with GCC to produce an executable, this does not cause the resulting
+ executable to be covered by the GNU General Public License. This
+ exception does not however invalidate any other reasons why the
+ executable file might be covered by the GNU General Public License. */
+
+#ifndef __objc_api_INCLUDE_GNU
+#define __objc_api_INCLUDE_GNU
+
+#include "objc/objc.h"
+#include "objc/hash.h"
+#include <stdio.h>
+
+/* For functions which return Method_t */
+#define METHOD_NULL (Method_t)0
+ /* Boolean typedefs */
+/*
+** Method descriptor returned by introspective Object methods.
+** This is really just the first part of the more complete objc_method
+** structure defined below and used internally by the runtime.
+*/
+struct objc_method_description
+{
+ SEL name; /* this is a selector, not a string */
+ char *types; /* type encoding */
+};
+
+
+
+/* Filer types used to describe Ivars and Methods. */
+#define _C_ID '@'
+#define _C_CLASS '#'
+#define _C_SEL ':'
+#define _C_CHR 'c'
+#define _C_UCHR 'C'
+#define _C_SHT 's'
+#define _C_USHT 'S'
+#define _C_INT 'i'
+#define _C_UINT 'I'
+#define _C_LNG 'l'
+#define _C_ULNG 'L'
+#define _C_FLT 'f'
+#define _C_DBL 'd'
+#define _C_BFLD 'b'
+#define _C_VOID 'v'
+#define _C_UNDEF '?'
+#define _C_PTR '^'
+#define _C_CHARPTR '*'
+#define _C_ATOM '%'
+#define _C_ARY_B '['
+#define _C_ARY_E ']'
+#define _C_UNION_B '('
+#define _C_UNION_E ')'
+#define _C_STRUCT_B '{'
+#define _C_STRUCT_E '}'
+
+
+
+/*
+** Set this variable nonzero to print a line describing each
+** message that is sent. (this is currently disabled)
+*/
+extern BOOL objc_trace;
+
+
+/*
+** Whereas a Module (defined further down) is the root (typically) of a file,
+** a Symtab is the root of the class and category definitions within the
+** module.
+**
+** A Symtab contains a variable length array of pointers to classes and
+** categories defined in the module.
+*/
+typedef struct objc_symtab {
+ unsigned long sel_ref_cnt; /* Unknown. */
+ SEL *refs; /* Unknown. */
+ unsigned short cls_def_cnt; /* Number of classes compiled
+ (defined) in the module. */
+ unsigned short cat_def_cnt; /* Number of categories
+ compiled (defined) in the
+ module. */
+ void *defs[1]; /* Variable array of pointers.
+ cls_def_cnt of type Class*
+ followed by cat_def_cnt of
+ type Category_t. */
+} Symtab, *Symtab_t;
+
+
+/*
+** The compiler generates one of these structures for each module that
+** composes the executable (eg main.m).
+**
+** This data structure is the root of the definition tree for the module.
+**
+** A collect program runs between ld stages and creates a ObjC ctor array.
+** That array holds a pointer to each module structure of the executable.
+*/
+typedef struct objc_module {
+ unsigned long version; /* Compiler revision. */
+ unsigned long size; /* sizeof(Module). */
+ const char* name; /* Name of the file where the
+ module was generated. The
+ name includes the path. */
+ Symtab_t symtab; /* Pointer to the Symtab of
+ the module. The Symtab
+ holds an array of pointers to
+ the classes and categories
+ defined in the module. */
+} Module, *Module_t;
+
+
+/*
+** The compiler generates one of these structures for a class that has
+** instance variables defined in its specification.
+*/
+typedef struct objc_ivar* Ivar_t;
+typedef struct objc_ivar_list {
+ int ivar_count; /* Number of structures (Ivar)
+ contained in the list. One
+ structure per instance
+ variable defined in the
+ class. */
+ struct objc_ivar {
+ const char* ivar_name; /* Name of the instance
+ variable as entered in the
+ class definition. */
+ const char* ivar_type; /* Description of the Ivar's
+ type. Useful for
+ debuggers. */
+ int ivar_offset; /* Byte offset from the base
+ address of the instance
+ structure to the variable. */
+
+ } ivar_list[1]; /* Variable length
+ structure. */
+} IvarList, *IvarList_t;
+
+
+/*
+** The compiler generates one (or more) of these structures for a class that
+** has methods defined in its specification.
+**
+** The implementation of a class can be broken into separate pieces in a file
+** and categories can break them across modules. To handle this problem is a
+** singly linked list of methods.
+*/
+typedef struct objc_method Method;
+typedef Method* Method_t;
+typedef struct objc_method_list {
+ struct objc_method_list* method_next; /* This variable is used to link
+ a method list to another. It
+ is a singly linked list. */
+ int method_count; /* Number of methods defined in
+ this structure. */
+ struct objc_method {
+ SEL method_name; /* This variable is the method's
+ name. It is a char*.
+ The unique integer passed to
+ objc_msg_send is a char* too.
+ It is compared against
+ method_name using strcmp. */
+ const char* method_types; /* Description of the method's
+ parameter list. Useful for
+ debuggers. */
+ IMP method_imp; /* Address of the method in the
+ executable. */
+ } method_list[1]; /* Variable length
+ structure. */
+} MethodList, *MethodList_t;
+
+struct objc_protocol_list {
+ struct objc_protocol_list *next;
+ int count;
+ Protocol *list[1];
+};
+
+/*
+** This is used to assure consistent access to the info field of
+** classes
+*/
+#ifndef HOST_BITS_PER_LONG
+#define HOST_BITS_PER_LONG (sizeof(long)*8)
+#endif
+
+#define __CLS_INFO(cls) ((cls)->info)
+#define __CLS_ISINFO(cls, mask) ((__CLS_INFO(cls)&mask)==mask)
+#define __CLS_SETINFO(cls, mask) (__CLS_INFO(cls) |= mask)
+
+/* The structure is of type MetaClass* */
+#define _CLS_META 0x2L
+#define CLS_ISMETA(cls) ((cls)&&__CLS_ISINFO(cls, _CLS_META))
+
+
+/* The structure is of type Class* */
+#define _CLS_CLASS 0x1L
+#define CLS_ISCLASS(cls) ((cls)&&__CLS_ISINFO(cls, _CLS_CLASS))
+
+/*
+** The class is initialized within the runtime. This means that
+** it has had correct super and sublinks assigned
+*/
+#define _CLS_RESOLV 0x8L
+#define CLS_ISRESOLV(cls) __CLS_ISINFO(cls, _CLS_RESOLV)
+#define CLS_SETRESOLV(cls) __CLS_SETINFO(cls, _CLS_RESOLV)
+
+/*
+** The class has been send a +initialize message or a such is not
+** defined for this class
+*/
+#define _CLS_INITIALIZED 0x04L
+#define CLS_ISINITIALIZED(cls) __CLS_ISINFO(cls, _CLS_INITIALIZED)
+#define CLS_SETINITIALIZED(cls) __CLS_SETINFO(cls, _CLS_INITIALIZED)
+
+/*
+** The class number of this class. This must be the same for both the
+** class and it's meta class object
+*/
+#define CLS_GETNUMBER(cls) (__CLS_INFO(cls) >> (HOST_BITS_PER_LONG/2))
+#define CLS_SETNUMBER(cls, num) \
+ ({ assert(CLS_GETNUMBER(cls)==0); \
+ __CLS_SETINFO(cls, (((unsigned long)num) << (HOST_BITS_PER_LONG/2))); })
+
+/*
+** The compiler generates one of these structures for each category. A class
+** may have many categories and contain both instance and factory methods.
+*/
+typedef struct objc_category {
+ const char* category_name; /* Name of the category. Name
+ contained in the () of the
+ category definition. */
+ const char* class_name; /* Name of the class to which
+ the category belongs. */
+ MethodList_t instance_methods; /* Linked list of instance
+ methods defined in the
+ category. NULL indicates no
+ instance methods defined. */
+ MethodList_t class_methods; /* Linked list of factory
+ methods defined in the
+ category. NULL indicates no
+ class methods defined. */
+ struct objc_protocol_list *protocols; /* List of Protocols
+ conformed to */
+} Category, *Category_t;
+
+/*
+** Structure used when a message is send to a class's super class. The
+** compiler generates one of these structures and passes it to
+** objc_msg_super.
+*/
+typedef struct objc_super {
+ id self; /* Id of the object sending
+ the message. */
+ Class* class; /* Object's super class. */
+} Super, *Super_t;
+
+IMP objc_msg_lookup_super(Super_t super, SEL sel);
+
+retval_t objc_msg_sendv(id, SEL, size_t, arglist_t);
+
+
+
+static const ARGSIZE = 96; /* for `method_get_argsize()' */
+
+/*
+** This is a hook which is called by objc_lookup_class and
+** objc_get_class if the runtime is not able to find the class.
+** This may e.g. try to load in the class using dynamic loading.
+** The function is guaranteed to be passed a non-NULL name string.
+*/
+extern Class* (*_objc_lookup_class)(const char *name);
+
+extern id (*_objc_object_alloc)(Class* class);
+
+extern id (*_objc_object_copy)(id object);
+
+extern id (*_objc_object_dispose)(id object);
+
+Method_t class_get_class_method(MetaClass* class, SEL aSel);
+
+Method_t class_get_instance_method(Class* class, SEL aSel);
+
+Class* class_pose_as(Class* impostor, Class* superclass);
+
+Class* objc_get_class(const char *name);
+
+Class* objc_lookup_class(const char *name);
+
+const char *sel_get_name(SEL selector);
+
+SEL sel_get_uid(const char *name);
+
+SEL sel_register_name(const char *name);
+
+BOOL sel_is_mapped (SEL aSel);
+
+extern id class_create_instance(Class* class);
+
+static inline const char *
+class_get_class_name(Class* class)
+{
+ return CLS_ISCLASS(class)?class->name:((class==Nil)?"Nil":0);
+}
+
+static inline long
+class_get_instance_size(Class* class)
+{
+ return CLS_ISCLASS(class)?class->instance_size:0;
+}
+
+static inline MetaClass*
+class_get_meta_class(Class* class)
+{
+ return CLS_ISCLASS(class)?class->class_pointer:Nil;
+}
+
+static inline Class*
+class_get_super_class(Class* class)
+{
+ return CLS_ISCLASS(class)?class->super_class:Nil;
+}
+
+static inline int
+class_get_version(Class* class)
+{
+ return CLS_ISCLASS(class)?class->version:-1;
+}
+
+static inline BOOL
+class_is_class(Class* class)
+{
+ return CLS_ISCLASS(class);
+}
+
+static inline BOOL
+class_is_meta_class(Class* class)
+{
+ return CLS_ISMETA(class);
+}
+
+
+static inline void
+class_set_version(Class* class, long version)
+{
+ if (CLS_ISCLASS(class))
+ class->version = version;
+}
+
+static inline unsigned int
+method_get_argsize(Method_t method)
+{
+ return ARGSIZE; /* This was a magic number (96)... */
+}
+
+static inline IMP
+method_get_imp(Method_t method)
+{
+ return (method!=METHOD_NULL)?method->method_imp:(IMP)0;
+}
+
+IMP get_imp (Class* class, SEL sel);
+
+id object_copy(id object);
+
+id object_dispose(id object);
+
+static inline Class*
+object_get_class(id object)
+{
+ return ((object!=nil)
+ ? (CLS_ISCLASS(object->class_pointer)
+ ? object->class_pointer
+ : (CLS_ISMETA(object->class_pointer)
+ ? (Class*)object
+ : Nil))
+ : Nil);
+}
+
+static inline const char *
+object_get_class_name(id object)
+{
+ return ((object!=nil)?(CLS_ISCLASS(object->class_pointer)
+ ?object->class_pointer->name
+ :((Class*)object)->name)
+ :"Nil");
+}
+
+static inline MetaClass*
+object_get_meta_class(id object)
+{
+ return ((object!=nil)?(CLS_ISCLASS(object->class_pointer)
+ ?object->class_pointer->class_pointer
+ :(CLS_ISMETA(object->class_pointer)
+ ?object->class_pointer
+ :Nil))
+ :Nil);
+}
+
+static inline Class*
+object_get_super_class
+(id object)
+{
+ return ((object!=nil)?(CLS_ISCLASS(object->class_pointer)
+ ?object->class_pointer->super_class
+ :(CLS_ISMETA(object->class_pointer)
+ ?((Class*)object)->super_class
+ :Nil))
+ :Nil);
+}
+
+static inline BOOL
+object_is_class(id object)
+{
+ return CLS_ISCLASS((Class*)object);
+}
+
+static inline BOOL
+object_is_instance(id object)
+{
+ return (object!=nil)&&CLS_ISCLASS(object->class_pointer);
+}
+
+static inline BOOL
+object_is_meta_class(id object)
+{
+ return CLS_ISMETA((Class*)object);
+}
+
+#endif /* not __objc_api_INCLUDE_GNU */
+
+
+
diff --git a/gnu/usr.bin/cc/libobjc/objc.h b/gnu/usr.bin/cc/libobjc/objc.h
new file mode 100644
index 000000000000..4bb9da361dec
--- /dev/null
+++ b/gnu/usr.bin/cc/libobjc/objc.h
@@ -0,0 +1,185 @@
+/* Basic data types for Objective C.
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* As a special exception, if you link this library with files
+ compiled with GCC to produce an executable, this does not cause
+ the resulting executable to be covered by the GNU General Public License.
+ This exception does not however invalidate any other reasons why
+ the executable file might be covered by the GNU General Public License. */
+
+#ifndef __objc_INCLUDE_GNU
+#define __objc_INCLUDE_GNU
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef IN_GCC
+#include "gstddef.h"
+#else
+#include "stddef.h"
+#endif
+
+/*
+** Definition of the boolean type.
+*/
+typedef char BOOL;
+#define YES (BOOL)1
+#define NO (BOOL)0
+
+/*
+** Definition of a selector. Selectors are really of type unsigned int.
+** The runtime does this mapping from SEL's to names internally in the
+** sel_... operations. You should never use the fact that it is actually
+** an integer, since other Objective-C implementations use other conventions.
+*/
+typedef void* SEL;
+
+/*
+** ObjC uses this typedef for untyped instances.
+*/
+typedef struct objc_object {
+ struct objc_class* class_pointer;
+} *id;
+
+/*
+** Definition of method type. When retrieving the implementation of a
+** method, this is type of the pointer returned
+*/
+typedef id (*IMP)(id, SEL, ...);
+
+/*
+** More simple types...
+*/
+#define nil (id)0 /* id of Nil instance */
+#define Nil (Class*)0 /* id of Nil class */
+typedef char *STR; /* String alias */
+
+/*
+** The compiler generates one of these structures for each class.
+**
+** This structure is the definition for classes.
+**
+** This structure is generated by the compiler in the executable and used by
+** the run-time during normal messaging operations. Therefore some members
+** change type. The compiler generates "char* const" and places a string in
+** the following member variables: super_class.
+*/
+typedef struct objc_class MetaClass;
+typedef struct objc_class Class;
+struct objc_class {
+ MetaClass* class_pointer; /* Pointer to the class's
+ meta class. */
+ struct objc_class* super_class; /* Pointer to the super
+ class. NULL for class
+ Object. */
+ const char* name; /* Name of the class. */
+ long version; /* Unknown. */
+ unsigned long info; /* Bit mask. See class masks
+ defined above. */
+ long instance_size; /* Size in bytes of the class.
+ The sum of the class definition
+ and all super class
+ definitions. */
+ struct objc_ivar_list* ivars; /* Pointer to a structure that
+ describes the instance
+ variables in the class
+ definition. NULL indicates
+ no instance variables. Does
+ not include super class
+ variables. */
+ struct objc_method_list* methods; /* Linked list of instance
+ methods defined for the
+ class. */
+ struct sarray * dtable; /* Pointer to instance
+ method dispatch table. */
+ struct objc_class* subclass_list; /* Subclasses */
+ struct objc_class* sibling_class;
+
+ struct objc_protocol_list *protocols; /* Protocols conformed to */
+};
+
+#ifndef __OBJC__
+typedef struct objc_protocol {
+ struct objc_class* class_pointer;
+ char *protocol_name;
+ struct objc_protocol_list *protocol_list;
+ struct objc_method_description_list *instance_methods, *class_methods;
+} Protocol;
+
+#else
+
+@class Protocol;
+#endif
+
+typedef void* retval_t; /* return value */
+typedef void(*apply_t)(void); /* function pointer */
+
+#if defined(REG_ARGS) || defined(STACK_ARGS)
+
+typedef struct {
+ char* arg_pointer;
+#ifdef STRUCT_RETURN
+ void* struct_return;
+#endif
+#ifdef REG_ARGS
+ void* regs[2];
+#endif
+} *arglist_t;
+
+#ifdef REG_ARGS
+#define __objc_frame_receiver(FRAME) (FRAME)->regs[0]
+#define __objc_frame_selector(FRAME) ((SEL)(FRAME)->regs[1])
+
+#else
+#define __objc_frame_receiver(FRAME) ((id*)(FRAME)->arg_pointer)[0]
+#define __objc_frame_selector(FRAME) ((SEL*)(FRAME)->arg_pointer)[1]
+#endif
+#else
+
+typedef void* arglist_t;
+
+#endif
+
+#if defined(__OBJC__)
+
+#include "objc/sarray.h"
+
+static id nil_method(id rcv, SEL op, ...) { return rcv; }
+
+extern __inline__ IMP
+objc_msg_lookup(id receiver, SEL op)
+{
+ if(receiver)
+ return sarray_get(receiver->class_pointer->dtable, (size_t) op);
+ else
+ return nil_method;
+}
+
+#else
+
+IMP objc_msg_lookup(id receiver, SEL op);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* not __objc_INCLUDE_GNU */
diff --git a/gnu/usr.bin/cc/libobjc/objects.c b/gnu/usr.bin/cc/libobjc/objects.c
new file mode 100644
index 000000000000..bd7a47e90523
--- /dev/null
+++ b/gnu/usr.bin/cc/libobjc/objects.c
@@ -0,0 +1,91 @@
+/* GNU Objective C Runtime class related functions
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+Author: Kresten Krab Thorup
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2, or (at your option) any later version.
+
+GNU CC 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 General Public License for more
+ details.
+
+You should have received a copy of the GNU General Public License along with
+ GNU CC; see the file COPYING. If not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* As a special exception, if you link this library with files compiled with
+ GCC to produce an executable, this does not cause the resulting executable
+ to be covered by the GNU General Public License. This exception does not
+ however invalidate any other reasons why the executable file might be
+ covered by the GNU General Public License. */
+
+#include "runtime.h" /* the kitchen sink */
+
+id __objc_object_alloc(Class*);
+id __objc_object_dispose(id);
+id __objc_object_copy(id);
+
+id (*_objc_object_alloc)(Class*) = __objc_object_alloc;
+id (*_objc_object_dispose)(id) = __objc_object_dispose;
+id (*_objc_object_copy)(id) = __objc_object_copy;
+
+id
+class_create_instance(Class* class)
+{
+ id new = nil;
+ if (CLS_ISCLASS(class))
+ new = (*_objc_object_alloc)(class);
+ if (new!=nil)
+ {
+ bzero (new, class->instance_size);
+ new->class_pointer = class;
+ }
+ return new;
+}
+
+id
+object_copy(id object)
+{
+ if ((object!=nil)&&CLS_ISCLASS(object->class_pointer))
+ return (*_objc_object_copy)(object);
+ else
+ return nil;
+}
+
+id
+object_dispose(id object)
+{
+ if ((object!=nil)&&CLS_ISCLASS(object->class_pointer))
+ {
+ if (_objc_object_dispose)
+ (*_objc_object_dispose)(object);
+ else
+ free(object);
+ }
+ return nil;
+}
+
+id __objc_object_alloc(Class* class)
+{
+ return (id)__objc_xmalloc(class->instance_size);
+}
+
+id __objc_object_dispose(id object)
+{
+ free(object);
+ return 0;
+}
+
+id __objc_object_copy(id object)
+{
+ id copy = class_create_instance(object->class_pointer);
+ memcpy(copy, object, object->class_pointer->instance_size);
+ return copy;
+}
+
+
diff --git a/gnu/usr.bin/cc/libobjc/runtime.h b/gnu/usr.bin/cc/libobjc/runtime.h
new file mode 100644
index 000000000000..cd9de6ac63f0
--- /dev/null
+++ b/gnu/usr.bin/cc/libobjc/runtime.h
@@ -0,0 +1,73 @@
+/* GNU Objective C Runtime internal declarations
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+Author: Kresten Krab Thorup
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2, or (at your option) any later version.
+
+GNU CC 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 General Public License for more
+ details.
+
+You should have received a copy of the GNU General Public License along with
+ GNU CC; see the file COPYING. If not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* As a special exception, if you link this library with files compiled with
+ GCC to produce an executable, this does not cause the resulting executable
+ to be covered by the GNU General Public License. This exception does not
+ however invalidate any other reasons why the executable file might be
+ covered by the GNU General Public License. */
+
+#ifndef __objc_runtime_INCLUDE_GNU
+#define __objc_runtime_INCLUDE_GNU
+
+#include "gstdarg.h" /* for varargs and va_list's */
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include "gstddef.h" /* so noone else will get system versions */
+#include "assert.h"
+
+#include "objc/objc.h" /* core data types */
+#include "objc/objc-api.h" /* runtime api functions */
+
+#include "objc/hash.h" /* hash structures */
+#include "objc/list.h" /* linear lists */
+
+extern void __objc_add_class_to_hash(Class*); /* (objc-class.c) */
+extern void __objc_init_selector_tables(); /* (objc-sel.c) */
+extern void __objc_init_class_tables(); /* (objc-class.c) */
+extern void __objc_init_dispatch_tables(); /* (objc-dispatch.c) */
+extern void __objc_install_premature_dtable(Class*); /* (objc-dispatch.c) */
+extern void __objc_resolve_class_links(); /* (objc-class.c) */
+extern void __objc_register_selectors_from_class(Class*); /* (objc-sel.c) */
+extern void __objc_update_dispatch_table_for_class (Class*);/* (objc-msg.c) */
+extern void class_add_method_list(Class*, MethodList_t);
+
+extern void objc_error(id object, const char* fmt, va_list);
+extern void (*_objc_error)(id, const char*, va_list);
+
+/* True when class links has been resolved */
+extern BOOL __objc_class_links_resolved;
+
+/* Number of selectors stored in each of the selector tables */
+extern int __objc_selector_max_index;
+
+#ifdef DEBUG
+#define DEBUG_PRINTF printf
+#else
+#define DEBUG_PRINTF
+#endif
+
+BOOL __objc_responds_to (id object, SEL sel); /* for internal use only! */
+
+#endif /* not __objc_runtime_INCLUDE_GNU */
+
+
diff --git a/gnu/usr.bin/cc/libobjc/sarray.c b/gnu/usr.bin/cc/libobjc/sarray.c
new file mode 100644
index 000000000000..e3b322ae0099
--- /dev/null
+++ b/gnu/usr.bin/cc/libobjc/sarray.c
@@ -0,0 +1,435 @@
+/* Sparse Arrays for Objective C dispatch tables
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* As a special exception, if you link this library with files
+ compiled with GCC to produce an executable, this does not cause
+ the resulting executable to be covered by the GNU General Public License.
+ This exception does not however invalidate any other reasons why
+ the executable file might be covered by the GNU General Public License. */
+
+#include "objc/sarray.h"
+#include <stdio.h>
+#include "assert.h"
+
+int nbuckets = 0;
+int nindices = 0;
+int narrays = 0;
+int idxsize = 0;
+
+#ifdef OBJC_SPARSE2
+const char* __objc_sparse2_id = "2 level sparse indices";
+#endif
+
+#ifdef OBJC_SPARSE3
+const char* __objc_sparse3_id = "3 level sparse indices";
+#endif
+
+void
+sarray_at_put(struct sarray* array, sidx index, void* element)
+{
+#ifdef OBJC_SPARSE3
+ struct sindex** the_index;
+#endif
+ struct sbucket** the_bucket;
+#ifdef OBJC_SPARSE3
+ size_t ioffset;
+#endif
+ size_t boffset;
+ size_t eoffset;
+#ifdef PRECOMPUTE_SELECTORS
+ union sofftype xx;
+ xx.idx = index;
+#ifdef OBJC_SPARSE3
+ ioffset = xx.off.ioffset;
+#endif
+ boffset = xx.off.boffset;
+ eoffset = xx.off.eoffset;
+#else /* not PRECOMPUTE_SELECTORS */
+#ifdef OBJC_SPARSE3
+ ioffset = index/INDEX_CAPACITY;
+ boffset = (index/BUCKET_SIZE)%INDEX_SIZE;
+ eoffset = index%BUCKET_SIZE;
+#else
+ boffset = index/BUCKET_SIZE;
+ eoffset = index%BUCKET_SIZE;
+#endif
+#endif /* not PRECOMPUTE_SELECTORS */
+
+ assert(soffset_decode(index) < array->capacity); /* Range check */
+
+#ifdef OBJC_SPARSE3
+ the_index = &(array->indices[ioffset]);
+ the_bucket = &((*the_index)->buckets[boffset]);
+#else
+ the_bucket = &(array->buckets[boffset]);
+#endif
+
+ if ((*the_bucket)->elems[eoffset] == element)
+ return; /* great! we just avoided a lazy copy */
+
+#ifdef OBJC_SPARSE3
+
+ /* First, perform lazy copy/allocation of index if needed */
+
+ if ((*the_index) == array->empty_index) {
+
+ /* The index was previously empty, allocate a new */
+ *the_index = (struct sindex*)__objc_xmalloc(sizeof(struct sindex));
+ memcpy(*the_index, array->empty_index, sizeof(struct sindex));
+ (*the_index)->version = array->version;
+ the_bucket = &((*the_index)->buckets[boffset]);
+ nindices += 1;
+
+ } else if ((*the_index)->version != array->version) {
+
+ /* This index must be lazy copied */
+ struct sindex* old_index = *the_index;
+ *the_index = (struct sindex*)__objc_xmalloc(sizeof(struct sindex));
+ memcpy( *the_index,old_index, sizeof(struct sindex));
+ (*the_index)->version = array->version;
+ the_bucket = &((*the_index)->buckets[boffset]);
+ nindices += 1;
+
+ }
+
+#endif /* OBJC_SPARSE3 */
+
+ /* next, perform lazy allocation/copy of the bucket if needed */
+
+ if ((*the_bucket) == array->empty_bucket) {
+
+ /* The bucket was previously empty (or something like that), */
+ /* allocate a new. This is the effect of `lazy' allocation */
+ *the_bucket = (struct sbucket*)__objc_xmalloc(sizeof(struct sbucket));
+ memcpy( *the_bucket,array->empty_bucket, sizeof(struct sbucket));
+ (*the_bucket)->version = array->version;
+ nbuckets += 1;
+
+ } else if ((*the_bucket)->version != array->version) {
+
+ /* Perform lazy copy. */
+ struct sbucket* old_bucket = *the_bucket;
+ *the_bucket = (struct sbucket*)__objc_xmalloc(sizeof(struct sbucket));
+ memcpy( *the_bucket,old_bucket, sizeof(struct sbucket));
+ (*the_bucket)->version = array->version;
+ nbuckets += 1;
+
+ }
+ (*the_bucket)->elems[eoffset] = element;
+}
+
+void
+sarray_at_put_safe(struct sarray* array, sidx index, void* element)
+{
+ if(soffset_decode(index) >= array->capacity)
+ sarray_realloc(array, soffset_decode(index)+1);
+ sarray_at_put(array, index, element);
+}
+
+struct sarray*
+sarray_new (int size, void* default_element)
+{
+#ifdef OBJC_SPARSE3
+ size_t num_indices = ((size-1)/(INDEX_CAPACITY))+1;
+#else /* OBJC_SPARSE2 */
+ size_t num_indices = ((size-1)/BUCKET_SIZE)+1;
+#endif
+ int counter;
+ struct sarray* arr;
+
+ assert(size > 0);
+
+ /* Allocate core array */
+ arr = (struct sarray*) __objc_xmalloc(sizeof(struct sarray));
+ arr->version = 0;
+ narrays += 1;
+
+ /* Initialize members */
+#ifdef OBJC_SPARSE3
+ arr->capacity = num_indices*INDEX_CAPACITY;
+ arr->indices = (struct sindex**)
+ __objc_xmalloc(sizeof(struct sindex*)*num_indices);
+ idxsize += num_indices;
+
+ arr->empty_index = (struct sindex*) __objc_xmalloc(sizeof(struct sindex));
+ arr->empty_index->version = 0;
+ nindices += 1;
+
+#else /* OBJC_SPARSE2 */
+ arr->capacity = num_indices*BUCKET_SIZE;
+ arr->buckets = (struct sbucket**)
+ __objc_xmalloc(sizeof(struct sbucket*)*num_indices);
+ idxsize += num_indices;
+
+#endif
+
+ arr->empty_bucket = (struct sbucket*) __objc_xmalloc(sizeof(struct sbucket));
+ arr->empty_bucket->version = 0;
+ nbuckets += 1;
+
+ arr->ref_count = 1;
+ arr->is_copy_of = (struct sarray*)0;
+
+ for (counter=0; counter<BUCKET_SIZE; counter++)
+ arr->empty_bucket->elems[counter] = default_element;
+
+#ifdef OBJC_SPARSE3
+ for (counter=0; counter<INDEX_SIZE; counter++)
+ arr->empty_index->buckets[counter] = arr->empty_bucket;
+
+ for (counter=0; counter<num_indices; counter++)
+ arr->indices[counter] = arr->empty_index;
+
+#else /* OBJC_SPARSE2 */
+
+ for (counter=0; counter<num_indices; counter++)
+ arr->buckets[counter] = arr->empty_bucket;
+
+#endif
+
+ return arr;
+}
+
+
+/* Reallocate the sparse array to hold `newsize' entries */
+
+void
+sarray_realloc(struct sarray* array, int newsize)
+{
+#ifdef OBJC_SPARSE3
+ int old_max_index = (array->capacity-1)/INDEX_CAPACITY;
+ int new_max_index = ((newsize-1)/INDEX_CAPACITY);
+ int rounded_size = (new_max_index+1)*INDEX_CAPACITY;
+
+#else /* OBJC_SPARSE2 */
+ int old_max_index = (array->capacity-1)/BUCKET_SIZE;
+ int new_max_index = ((newsize-1)/BUCKET_SIZE);
+ int rounded_size = (new_max_index+1)*BUCKET_SIZE;
+
+#endif
+
+ int counter;
+
+ assert(newsize > 0);
+
+ /* The size is the same, just ignore the request */
+ if(rounded_size == array->capacity)
+ return;
+
+ assert(array->ref_count == 1); /* stop if lazy copied... */
+
+ if(rounded_size < array->capacity)
+ {
+ /* update capacity */
+ array->capacity = rounded_size;
+
+ /* free buckets above new_max_index */
+ for(counter = old_max_index; counter > new_max_index; counter-- ) {
+#ifdef OBJC_SPARSE3
+ struct sindex* idx = array->indices[counter];
+ if((idx != array->empty_index) && (idx->version == array->version)) {
+ int c2;
+ for(c2=0; c2<INDEX_SIZE; c2++) {
+ struct sbucket* bkt = idx->buckets[c2];
+ if((bkt != array->empty_bucket) && (bkt->version == array->version))
+ {
+ free(bkt);
+ nbuckets -= 1;
+ }
+ }
+ free(idx);
+ nindices -= 1;
+ }
+#else /* OBJC_SPARSE2 */
+ struct sbucket* bkt = array->buckets[counter];
+ if ((bkt != array->empty_bucket) && (bkt->version == array->version))
+ {
+ free(bkt);
+ nbuckets -= 1;
+ }
+#endif
+ }
+
+#ifdef OBJC_SPARSE3
+ /* realloc to free the space above new_max_index */
+ array->indices = (struct sindex**)
+ __objc_xrealloc(array->indices,
+ (new_max_index+1)*sizeof(struct sindex*));
+#else /* OBJC_SPARSE2 */
+ array->buckets = (struct sbucket**)
+ __objc_xrealloc(array->buckets,
+ (new_max_index+1)*sizeof(struct sbucket*));
+#endif
+ idxsize -= (old_max_index-new_max_index);
+
+ return;
+ }
+
+ /* We are asked to extend the array -- reallocate the bucket table, */
+ /* and insert empty_bucket in newly allocated places. */
+ if(rounded_size > array->capacity)
+ {
+ /* update capacity */
+ array->capacity = rounded_size;
+
+#ifdef OBJC_SPARSE3
+ /* realloc to make room in table above old_max_index */
+ array->indices = (struct sindex**)
+ __objc_xrealloc(array->indices,
+ (new_max_index+1)*sizeof(struct sindex*));
+
+ /* reset entries above old_max_index to empty_bucket */
+ for(counter = old_max_index+1; counter <= new_max_index; counter++)
+ array->indices[counter] = array->empty_index;
+
+#else /* OBJC_SPARSE2 */
+
+ /* realloc to make room in table above old_max_index */
+ array->buckets = (struct sbucket**)
+ __objc_xrealloc(array->buckets,
+ (new_max_index+1)*sizeof(struct sbucket*));
+
+ /* reset entries above old_max_index to empty_bucket */
+ for(counter = old_max_index+1; counter <= new_max_index; counter++)
+ array->buckets[counter] = array->empty_bucket;
+
+#endif
+ idxsize += (new_max_index-old_max_index);
+ return;
+ }
+}
+
+
+/* Free a sparse array allocated with sarray_new */
+
+void
+sarray_free(struct sarray* array) {
+#ifdef OBJC_SPARSE3
+ size_t old_max_index = (array->capacity-1)/INDEX_CAPACITY;
+#else
+ size_t old_max_index = (array->capacity-1)/BUCKET_SIZE;
+#endif
+ int counter = 0;
+
+ assert(array->ref_count != 0); /* Freed multiple times!!! */
+
+ if(--(array->ref_count) != 0) /* There exists copies of me */
+ return;
+
+ if((array->is_copy_of) && ((array->is_copy_of->ref_count - 1) == 0))
+ sarray_free(array->is_copy_of);
+
+ /* Free all entries that do not point to empty_bucket */
+ for(counter = 0; counter <= old_max_index; counter++ ) {
+#ifdef OBJC_SPARSE3
+ struct sindex* idx = array->indices[counter];
+ if((idx != array->empty_index) && (idx->version == array->version)) {
+ int c2;
+ for(c2=0; c2<INDEX_SIZE; c2++) {
+ struct sbucket* bkt = idx->buckets[c2];
+ if((bkt != array->empty_bucket) && (bkt->version == array->version))
+ {
+ free(bkt);
+ nbuckets -= 1;
+ }
+ }
+ free(idx);
+ nindices -= 1;
+ }
+#else /* OBJC_SPARSE2 */
+ struct sbucket* bkt = array->buckets[counter];
+ if ((bkt != array->empty_bucket) && (bkt->version == array->version))
+ {
+ free(bkt);
+ nbuckets -= 1;
+ }
+#endif
+ }
+
+#ifdef OBJC_SPARSE3
+ /* free empty_index */
+ if(array->empty_index->version == array->version) {
+ free(array->empty_index);
+ nindices -= 1;
+ }
+#endif
+
+ /* free empty_bucket */
+ if(array->empty_bucket->version == array->version) {
+ free(array->empty_bucket);
+ nbuckets -= 1;
+ }
+
+#ifdef OBJC_SPARSE3
+ /* free bucket table */
+ free(array->indices);
+ idxsize -= (old_max_index+1);
+
+#else
+ /* free bucket table */
+ free(array->buckets);
+ idxsize -= (old_max_index+1);
+
+#endif
+
+ /* free array */
+ free(array);
+ narrays -= 1;
+}
+
+/* This is a lazy copy. Only the core of the structure is actually */
+/* copied. */
+
+struct sarray*
+sarray_lazy_copy(struct sarray* oarr)
+{
+#ifdef OBJC_SPARSE3
+ size_t num_indices = ((oarr->capacity-1)/INDEX_CAPACITY)+1;
+#else /* OBJC_SPARSE2 */
+ size_t num_indices = ((oarr->capacity-1)/BUCKET_SIZE)+1;
+#endif
+ struct sarray* arr;
+
+ /* Allocate core array */
+ arr = (struct sarray*) __objc_xmalloc(sizeof(struct sarray));
+ memcpy( arr,oarr, sizeof(struct sarray));
+ arr->version = oarr->version + 1;
+ arr->is_copy_of = oarr;
+ oarr->ref_count += 1;
+ arr->ref_count = 1;
+
+#ifdef OBJC_SPARSE3
+ /* Copy bucket table */
+ arr->indices = (struct sindex**)
+ __objc_xmalloc(sizeof(struct sindex*)*num_indices);
+ memcpy( arr->indices,oarr->indices,
+ sizeof(struct sindex*)*num_indices);
+#else
+ /* Copy bucket table */
+ arr->buckets = (struct sbucket**)
+ __objc_xmalloc(sizeof(struct sbucket*)*num_indices);
+ memcpy( arr->buckets,oarr->buckets,
+ sizeof(struct sbucket*)*num_indices);
+#endif
+
+ idxsize += num_indices;
+ narrays += 1;
+
+ return arr;
+}
diff --git a/gnu/usr.bin/cc/libobjc/sarray.h b/gnu/usr.bin/cc/libobjc/sarray.h
new file mode 100644
index 000000000000..05d28cea8b0c
--- /dev/null
+++ b/gnu/usr.bin/cc/libobjc/sarray.h
@@ -0,0 +1,235 @@
+/* Sparse Arrays for Objective C dispatch tables
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+Author: Kresten Krab Thorup
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* As a special exception, if you link this library with files
+ compiled with GCC to produce an executable, this does not cause
+ the resulting executable to be covered by the GNU General Public License.
+ This exception does not however invalidate any other reasons why
+ the executable file might be covered by the GNU General Public License. */
+
+#ifndef __sarray_INCLUDE_GNU
+#define __sarray_INCLUDE_GNU
+
+#define OBJC_SPARSE2 /* 2-level sparse array */
+/* #define OBJC_SPARSE3 */ /* 3-level sparse array */
+
+#ifdef OBJC_SPARSE2
+extern const char* __objc_sparse2_id;
+#endif
+
+#ifdef OBJC_SPARSE3
+extern const char* __objc_sparse3_id;
+#endif
+
+#ifdef IN_GCC
+#include "gstddef.h"
+#else
+#include "stddef.h"
+#endif
+
+extern int nbuckets; /* for stats */
+extern int nindices;
+extern int narrays;
+extern int idxsize;
+
+#include <assert.h>
+
+/* An unsigned integer of same size as a pointer */
+#define SIZET_BITS (sizeof(size_t)*8)
+
+#if defined(sparc) || defined(OBJC_SPARSE2)
+#define PRECOMPUTE_SELECTORS
+#endif
+
+#ifdef OBJC_SPARSE3
+
+/* Buckets are 8 words each */
+#define BUCKET_BITS 3
+#define BUCKET_SIZE (1<<BUCKET_BITS)
+#define BUCKET_MASK (BUCKET_SIZE-1)
+
+/* Indices are 16 words each */
+#define INDEX_BITS 4
+#define INDEX_SIZE (1<<INDEX_BITS)
+#define INDEX_MASK (INDEX_SIZE-1)
+
+#define INDEX_CAPACITY (BUCKET_SIZE*INDEX_SIZE)
+
+#else /* OBJC_SPARSE2 */
+
+/* Buckets are 32 words each */
+#define BUCKET_BITS 5
+#define BUCKET_SIZE (1<<BUCKET_BITS)
+#define BUCKET_MASK (BUCKET_SIZE-1)
+
+#endif /* OBJC_SPARSE2 */
+
+typedef size_t sidx;
+
+#ifdef PRECOMPUTE_SELECTORS
+
+struct soffset {
+#ifdef OBJC_SPARSE3
+ unsigned int unused : SIZET_BITS/4;
+ unsigned int eoffset : SIZET_BITS/4;
+ unsigned int boffset : SIZET_BITS/4;
+ unsigned int ioffset : SIZET_BITS/4;
+#else /* OBJC_SPARSE2 */
+#ifdef sparc
+ unsigned int boffset : (SIZET_BITS - 2) - BUCKET_BITS;
+ unsigned int eoffset : BUCKET_BITS;
+ unsigned int unused : 2;
+#else
+ unsigned int boffset : SIZET_BITS/2;
+ unsigned int eoffset : SIZET_BITS/2;
+#endif
+#endif /* OBJC_SPARSE2 */
+};
+
+union sofftype {
+ struct soffset off;
+ sidx idx;
+};
+
+#endif /* not PRECOMPUTE_SELECTORS */
+
+void * __objc_xrealloc (void *optr, size_t size);
+void * __objc_xmalloc (size_t size);
+
+struct sbucket {
+ void* elems[BUCKET_SIZE]; /* elements stored in array */
+ short version; /* used for copy-on-write */
+};
+
+#ifdef OBJC_SPARSE3
+
+struct sindex {
+ struct sbucket* buckets[INDEX_SIZE];
+ short version;
+};
+
+#endif /* OBJC_SPARSE3 */
+
+struct sarray {
+#ifdef OBJC_SPARSE3
+ struct sindex** indices;
+ struct sindex* empty_index;
+#else /* OBJC_SPARSE2 */
+ struct sbucket** buckets;
+#endif /* OBJC_SPARSE2 */
+ struct sbucket* empty_bucket;
+ short version;
+ short ref_count;
+ struct sarray* is_copy_of;
+ int capacity;
+};
+
+struct sarray* sarray_new(int, void* default_element);
+void sarray_free(struct sarray*);
+struct sarray* sarray_lazy_copy(struct sarray*);
+struct sarray* sarray_hard_copy(struct sarray*); /* ... like the name? */
+void sarray_realloc(struct sarray*, int new_size);
+void sarray_at_put(struct sarray*, sidx index, void* elem);
+void sarray_at_put_safe(struct sarray*, sidx index, void* elem);
+
+
+#ifdef PRECOMPUTE_SELECTORS
+/* Transform soffset values to ints and vica verca */
+static inline unsigned int
+soffset_decode(sidx index)
+{
+ union sofftype x;
+ x.idx = index;
+#ifdef OBJC_SPARSE3
+ return x.off.eoffset
+ + (x.off.boffset*BUCKET_SIZE)
+ + (x.off.ioffset*INDEX_CAPACITY);
+#else /* OBJC_SPARSE2 */
+ return x.off.eoffset + (x.off.boffset*BUCKET_SIZE);
+#endif /* OBJC_SPARSE2 */
+}
+
+static inline sidx
+soffset_encode(size_t offset)
+{
+ union sofftype x;
+ x.off.eoffset = offset%BUCKET_SIZE;
+#ifdef OBJC_SPARSE3
+ x.off.boffset = (offset/BUCKET_SIZE)%INDEX_SIZE;
+ x.off.ioffset = offset/INDEX_CAPACITY;
+#else /* OBJC_SPARSE2 */
+ x.off.boffset = offset/BUCKET_SIZE;
+#endif
+ return (sidx)x.idx;
+}
+
+#else /* not PRECOMPUTE_SELECTORS */
+
+static inline size_t
+soffset_decode(sidx index)
+{
+ return index;
+}
+
+static inline sidx
+soffset_encode(size_t offset)
+{
+ return offset;
+}
+#endif /* not PRECOMPUTE_SELECTORS */
+
+/* Get element from the Sparse array `array' at offset `index' */
+
+static inline void* sarray_get(struct sarray* array, sidx index)
+{
+#ifdef PRECOMPUTE_SELECTORS
+ union sofftype x;
+ x.idx = index;
+#ifdef OBJC_SPARSE3
+ return
+ array->
+ indices[x.off.ioffset]->
+ buckets[x.off.boffset]->
+ elems[x.off.eoffset];
+#else /* OBJC_SPARSE2 */
+ return array->buckets[x.off.boffset]->elems[x.off.eoffset];
+#endif /* OBJC_SPARSE2 */
+#else /* not PRECOMPUTE_SELECTORS */
+#ifdef OBJC_SPARSE3
+ return array->
+ indices[index/INDEX_CAPACITY]->
+ buckets[(index/BUCKET_SIZE)%INDEX_SIZE]->
+ elems[index%BUCKET_SIZE];
+#else /* OBJC_SPARSE2 */
+ return array->buckets[index/BUCKET_SIZE]->elems[index%BUCKET_SIZE];
+#endif /* not OBJC_SPARSE3 */
+#endif /* not PRECOMPUTE_SELECTORS */
+}
+
+static inline void* sarray_get_safe(struct sarray* array, sidx index)
+{
+ if(soffset_decode(index) < array->capacity)
+ return sarray_get(array, index);
+ else
+ return (array->empty_bucket->elems[0]);
+}
+
+#endif /* __sarray_INCLUDE_GNU */
diff --git a/gnu/usr.bin/cc/libobjc/selector.c b/gnu/usr.bin/cc/libobjc/selector.c
new file mode 100644
index 000000000000..40bc7a338c32
--- /dev/null
+++ b/gnu/usr.bin/cc/libobjc/selector.c
@@ -0,0 +1,139 @@
+/* GNU Objective C Runtime selector related functions
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+Author: Kresten Krab Thorup
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2, or (at your option) any later version.
+
+GNU CC 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 General Public License for more
+ details.
+
+You should have received a copy of the GNU General Public License along with
+ GNU CC; see the file COPYING. If not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* As a special exception, if you link this library with files compiled with
+ GCC to produce an executable, this does not cause the resulting executable
+ to be covered by the GNU General Public License. This exception does not
+ however invalidate any other reasons why the executable file might be
+ covered by the GNU General Public License. */
+
+#include "runtime.h"
+#include "objc/sarray.h"
+
+/* Initial selector hash table size. Value doesnt matter much */
+#define SELECTOR_HASH_SIZE 128
+
+/* Tables mapping selector names to uid and opposite */
+static struct sarray* __objc_selector_array = 0; /* uid -> name */
+static cache_ptr __objc_selector_hash = 0; /* name -> uid */
+
+static void register_selectors_from_list(MethodList_t);
+
+/* Number of selectors stored in each of the above tables */
+int __objc_selector_max_index = 0;
+
+void __objc_init_selector_tables()
+{
+ __objc_selector_array = sarray_new (SELECTOR_HASH_SIZE, 0);
+ __objc_selector_hash
+ = hash_new (SELECTOR_HASH_SIZE,
+ (hash_func_type) hash_string,
+ (compare_func_type) compare_strings);
+}
+
+/* This routine is given a class and records all of the methods in its class
+ structure in the record table. */
+void
+__objc_register_selectors_from_class (Class* class)
+{
+ MethodList_t method_list;
+
+ method_list = class->methods;
+ while (method_list)
+ {
+ register_selectors_from_list (method_list);
+ method_list = method_list->method_next;
+ }
+}
+
+
+/* This routine is given a list of methods and records each of the methods in
+ the record table. This is the routine that does the actual recording
+ work.
+
+ This one is only called for Class objects. For categories,
+ class_add_method_list is called.
+ */
+static void
+register_selectors_from_list (MethodList_t method_list)
+{
+ int i = 0;
+ while (i < method_list->method_count)
+ {
+ Method_t method = &method_list->method_list[i];
+ method->method_name = sel_register_name ((char*)method->method_name);
+ i += 1;
+ }
+}
+
+/* return selector representing name */
+SEL
+sel_get_uid (const char *name)
+{
+ return (SEL) hash_value_for_key (__objc_selector_hash, name);
+}
+
+/* Get name of selector. If selector is unknown, the empty string ""
+ is returned */
+const char*
+sel_get_name (SEL selector)
+{
+ if ((soffset_decode((sidx)selector) > 0)
+ && (soffset_decode((sidx)selector) <= __objc_selector_max_index))
+ return sarray_get (__objc_selector_array, (sidx) selector);
+ else
+ return NULL;
+}
+
+BOOL
+sel_is_mapped (SEL selector)
+{
+ unsigned int idx = soffset_decode ((sidx)selector);
+ return ((idx > 0) && (idx <= __objc_selector_max_index));
+}
+
+/* The uninstalled dispatch table */
+extern struct sarray* __objc_uninstalled_dtable;
+
+/* Store the passed selector name in the selector record and return its
+ selector value (value returned by sel_get_uid). */
+SEL
+sel_register_name (const char *sel)
+{
+ SEL j;
+ sidx i;
+
+ if ((j = sel_get_uid ((const char *) sel)))
+ return j;
+
+ /* Save the selector name. */
+ __objc_selector_max_index += 1;
+ i = soffset_encode(__objc_selector_max_index);
+
+ DEBUG_PRINTF ("Record selector %s as: %#x\n", sel, i);
+
+ sarray_at_put_safe (__objc_selector_array, i, (void *) sel);
+ hash_add (&__objc_selector_hash, (void *) sel, (void *) i);
+
+ sarray_realloc(__objc_uninstalled_dtable, __objc_selector_max_index+1);
+
+ return (SEL) i;
+}
+
diff --git a/gnu/usr.bin/cc/libobjc/sendmsg.c b/gnu/usr.bin/cc/libobjc/sendmsg.c
new file mode 100644
index 000000000000..e2c52ba4c71f
--- /dev/null
+++ b/gnu/usr.bin/cc/libobjc/sendmsg.c
@@ -0,0 +1,471 @@
+/* GNU Objective C Runtime message lookup
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+Author: Kresten Krab Thorup
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2, or (at your option) any later version.
+
+GNU CC 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 General Public License for more
+ details.
+
+You should have received a copy of the GNU General Public License along with
+ GNU CC; see the file COPYING. If not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* As a special exception, if you link this library with files compiled with
+ GCC to produce an executable, this does not cause the resulting executable
+ to be covered by the GNU General Public License. This exception does not
+ however invalidate any other reasons why the executable file might be
+ covered by the GNU General Public License. */
+
+#include "runtime.h"
+#include "sarray.h"
+
+/* The uninstalled dispatch table */
+struct sarray* __objc_uninstalled_dtable = 0;
+
+/* Send +initialize to class */
+static void __objc_send_initialize(Class*);
+
+static void __objc_install_dispatch_table_for_class (Class*);
+
+/* Forward declare some functions */
+static void __objc_init_install_dtable(id, SEL);
+static id __objc_missing_method(id, SEL, ...);
+static Method_t search_for_method_in_hierarchy (Class* class, SEL sel);
+static Method_t search_for_method_in_list(MethodList_t list, SEL op);
+id nil_method(id, SEL, ...);
+
+id
+nil_method(id receiver, SEL op, ...)
+{
+ return receiver;
+}
+
+/* Given a class and selector, return the selector's implementation. */
+__inline__ IMP
+get_imp (Class* class, SEL sel)
+{
+ void* res = sarray_get (class->dtable, (size_t) sel);
+ if(res == __objc_init_install_dtable)
+ __objc_install_dispatch_table_for_class (class);
+ return sarray_get (class->dtable, (size_t) sel);
+}
+
+__inline__ BOOL
+__objc_responds_to (id object, SEL sel)
+{
+ return get_imp (object->class_pointer, sel) != __objc_missing_method;
+}
+
+/* This is the lookup function. All entries in the table are either a
+ valid method *or* one of `__objc_missing_method' which calls
+ forward:: etc, or `__objc_init_install_dtable' which installs the
+ real dtable */
+__inline__ IMP
+objc_msg_lookup(id receiver, SEL op)
+{
+ if(receiver)
+ return sarray_get(receiver->class_pointer->dtable, (sidx)op);
+ else
+ return nil_method;
+}
+
+IMP
+objc_msg_lookup_super (Super_t super, SEL sel)
+{
+ if (super->self)
+ return get_imp (super->class, sel);
+ else
+ return nil_method;
+}
+
+retval_t
+objc_msg_sendv(id object, SEL op, size_t frame_size, arglist_t arg_frame)
+{
+#ifdef __objc_frame_receiver
+ __objc_frame_receiver(arg_frame) = object;
+ __objc_frame_selector(arg_frame) = op;
+ return __builtin_apply((apply_t)get_imp(object->class_pointer, op),
+ arg_frame,
+ frame_size);
+#else
+#warning performv:: will not work
+ va_list nothing;
+ (*_objc_error)(object, "objc_msg_sendv (performv::) not supported\n", nothing);
+ return 0;
+#endif
+}
+
+void __objc_init_dispatch_tables()
+{
+ __objc_uninstalled_dtable
+ = sarray_new(200, __objc_init_install_dtable);
+}
+
+/* This one is a bit hairy. This function is installed in the
+ premature dispatch table, and thus called once for each class,
+ namely when the very first message is send to it. */
+
+static void __objc_init_install_dtable(id receiver, SEL op)
+{
+ __label__ allready_initialized;
+ IMP imp;
+ void* args;
+ void* result;
+
+ /* This may happen, if the programmer has taken the address of a
+ method before the dtable was initialized... too bad for him! */
+ if(receiver->class_pointer->dtable != __objc_uninstalled_dtable)
+ goto allready_initialized;
+
+ if(CLS_ISCLASS(receiver->class_pointer))
+ {
+ /* receiver is an ordinary object */
+ assert(CLS_ISCLASS(receiver->class_pointer));
+
+ /* install instance methods table */
+ __objc_install_dispatch_table_for_class (receiver->class_pointer);
+
+ /* call +initialize -- this will in turn install the factory
+ dispatch table if not already done :-) */
+ __objc_send_initialize(receiver->class_pointer);
+ }
+ else
+ {
+ /* receiver is a class object */
+ assert(CLS_ISCLASS((Class*)receiver));
+ assert(CLS_ISMETA(receiver->class_pointer));
+
+ /* Install real dtable for factory methods */
+ __objc_install_dispatch_table_for_class (receiver->class_pointer);
+
+ if(op != sel_get_uid ("initialize"))
+ __objc_send_initialize((Class*)receiver);
+ else
+ CLS_SETINITIALIZED((Class*)receiver);
+ }
+
+allready_initialized:
+
+ /* Get real method for this in newly installed dtable */
+ imp = get_imp(receiver->class_pointer, op);
+
+ args = __builtin_apply_args();
+ result = __builtin_apply((apply_t)imp, args, 96);
+ __builtin_return (result);
+
+}
+
+/* Install dummy table for class which causes the first message to
+ that class (or instances hereof) to be initialized properly */
+void __objc_install_premature_dtable(Class* class)
+{
+ assert(__objc_uninstalled_dtable);
+ class->dtable = __objc_uninstalled_dtable;
+}
+
+/* Send +initialize to class if not already done */
+static void __objc_send_initialize(Class* class)
+{
+ Method_t m;
+
+ /* This *must* be a class object */
+ assert(CLS_ISCLASS(class));
+ assert(!CLS_ISMETA(class));
+
+ if (!CLS_ISINITIALIZED(class))
+ {
+ CLS_SETINITIALIZED(class);
+ CLS_SETINITIALIZED(class->class_pointer);
+
+ if(class->super_class)
+ __objc_send_initialize(class->super_class);
+
+ {
+ MethodList_t method_list = class->class_pointer->methods;
+ SEL op = sel_register_name ("initialize");
+
+ /* If not found then we'll search the list. */
+ while (method_list)
+ {
+ int i;
+
+ /* Search the method list. */
+ for (i = 0; i < method_list->method_count; ++i)
+ {
+ Method_t method = &method_list->method_list[i];
+
+
+ if (method->method_name == op)
+ (*method->method_imp)((id) class, op);
+ }
+
+ /* The method wasn't found. Follow the link to the next list of
+ methods. */
+ method_list = method_list->method_next;
+ }
+ }
+ }
+}
+
+static void
+__objc_install_dispatch_table_for_class (Class* class)
+{
+ Class* super;
+ MethodList_t mlist;
+ int counter;
+
+ /* If the class has not yet had it's class links resolved, we must
+ re-compute all class links */
+ if(!CLS_ISRESOLV(class))
+ __objc_resolve_class_links();
+
+ super = class->super_class;
+
+ if (super != 0 && (super->dtable == __objc_uninstalled_dtable))
+ __objc_install_dispatch_table_for_class (super);
+
+ /* Allocate dtable if nessecary */
+ if (super == 0)
+ {
+ class->dtable = sarray_new (__objc_selector_max_index,
+ __objc_missing_method);
+ }
+ else
+ class->dtable = sarray_lazy_copy (super->dtable);
+
+ for (mlist = class->methods; mlist; mlist = mlist->method_next)
+ {
+ counter = mlist->method_count - 1;
+ while (counter >= 0)
+ {
+ Method_t method = &(mlist->method_list[counter]);
+ sarray_at_put (class->dtable,
+ (sidx) method->method_name,
+ method->method_imp);
+ counter -= 1;
+ }
+ }
+}
+
+void __objc_update_dispatch_table_for_class (Class* class)
+{
+ Class* next;
+ struct sarray* save;
+
+ /* not yet installed -- skip it */
+ if (class->dtable == __objc_uninstalled_dtable)
+ return;
+
+ save = class->dtable;
+ __objc_install_premature_dtable (class);
+ sarray_free (save);
+
+
+ if (class->subclass_list) /* Traverse subclasses */
+ for (next = class->subclass_list; next; next = next->sibling_class)
+ __objc_update_dispatch_table_for_class (next);
+}
+
+
+/* This function adds a method list to a class. This function is
+ typically called by another function specific to the run-time. As
+ such this function does not worry about thread safe issued.
+
+ This one is only called for categories. Class objects have their
+ methods installed rightaway, and their selectors are made into
+ SEL's by the function __objc_register_selectors_from_class. */
+void
+class_add_method_list (Class* class, MethodList_t list)
+{
+ int i;
+ static SEL initialize_sel = 0;
+ if (!initialize_sel)
+ initialize_sel = sel_register_name ("initialize");
+
+ /* Passing of a linked list is not allowed. Do multiple calls. */
+ assert (!list->method_next);
+
+ /* Check for duplicates. */
+ for (i = 0; i < list->method_count; ++i)
+ {
+ Method_t method = &list->method_list[i];
+
+ if (method->method_name) /* Sometimes these are NULL */
+ {
+ /* This is where selector names are transmogriffed to SEL's */
+ method->method_name = sel_register_name ((char*)method->method_name);
+
+ if (search_for_method_in_list (class->methods, method->method_name)
+ && method->method_name != initialize_sel)
+ {
+ /* Duplication. Print a error message an change the method name
+ to NULL. */
+ fprintf (stderr, "attempt to add a existing method: %s\n",
+ sel_get_name(method->method_name));
+ method->method_name = 0;
+ }
+ }
+ }
+
+ /* Add the methods to the class's method list. */
+ list->method_next = class->methods;
+ class->methods = list;
+}
+
+
+Method_t
+class_get_instance_method(Class* class, SEL op)
+{
+ return search_for_method_in_hierarchy(class, op);
+}
+
+Method_t
+class_get_class_method(MetaClass* class, SEL op)
+{
+ return search_for_method_in_hierarchy(class, op);
+}
+
+
+/* Search for a method starting from the current class up its hierarchy.
+ Return a pointer to the method's method structure if found. NULL
+ otherwise. */
+
+static Method_t
+search_for_method_in_hierarchy (Class* cls, SEL sel)
+{
+ Method_t method = NULL;
+ Class* class;
+
+ if (! sel_is_mapped (sel))
+ return NULL;
+
+ /* Scan the method list of the class. If the method isn't found in the
+ list then step to its super class. */
+ for (class = cls; ((! method) && class); class = class->super_class)
+ method = search_for_method_in_list (class->methods, sel);
+
+ return method;
+}
+
+
+
+/* Given a linked list of method and a method's name. Search for the named
+ method's method structure. Return a pointer to the method's method
+ structure if found. NULL otherwise. */
+static Method_t
+search_for_method_in_list (MethodList_t list, SEL op)
+{
+ MethodList_t method_list = list;
+
+ if (! sel_is_mapped (op))
+ return NULL;
+
+ /* If not found then we'll search the list. */
+ while (method_list)
+ {
+ int i;
+
+ /* Search the method list. */
+ for (i = 0; i < method_list->method_count; ++i)
+ {
+ Method_t method = &method_list->method_list[i];
+
+ if (method->method_name)
+ if (method->method_name == op)
+ return method;
+ }
+
+ /* The method wasn't found. Follow the link to the next list of
+ methods. */
+ method_list = method_list->method_next;
+ }
+
+ return NULL;
+}
+
+
+/* This fuction is installed in the dispatch table for all methods which are
+ not implemented. Thus, it is called when a selector is not recognized. */
+static id
+__objc_missing_method (id object, SEL sel, ...)
+{
+ IMP imp;
+ SEL frwd_sel;
+ SEL err_sel;
+
+ /* first try if the object understands forward:: */
+ frwd_sel = sel_get_uid("forward::");
+ imp = get_imp(object->class_pointer, frwd_sel);
+ if(imp != __objc_missing_method)
+ {
+ void *result, *args = __builtin_apply_args();
+ result = (*imp)(object, frwd_sel, sel, args);
+ __builtin_return(result);
+ }
+
+ /* If the object recognizes the doesNotRecognize: method then we're going
+ to send it. */
+ err_sel = sel_get_uid ("doesNotRecognize:");
+ imp = get_imp (object->class_pointer, err_sel);
+ if (imp != __objc_missing_method)
+ {
+ return (*imp) (object, err_sel, sel);
+ }
+
+ /* The object doesn't recognize the method. Check for responding to
+ error:. If it does then sent it. */
+ {
+ char msg[256 + strlen ((char*)sel_get_name (sel))
+ + strlen ((char*)object->class_pointer->name)];
+
+ sprintf (msg, "(%s) %s does not recognize %s",
+ (CLS_ISMETA(object->class_pointer)
+ ? "class"
+ : "instance" ),
+ object->class_pointer->name, sel_get_name (sel));
+
+ err_sel = sel_get_uid ("error:");
+ imp = get_imp (object->class_pointer, err_sel);
+ if (imp != __objc_missing_method)
+ return (*imp) (object, sel_get_uid ("error:"), msg);
+
+ /* The object doesn't respond to doesNotRecognize: or error:; Therefore,
+ a default action is taken. */
+ fprintf (stderr, "fatal: %s\n", msg);
+ abort ();
+ }
+}
+
+void __objc_print_dtable_stats()
+{
+ int total = 0;
+ printf("memory usage: (%s)\n",
+#ifdef OBJC_SPARSE2
+ "2-level sparse arrays"
+#else
+ "3-level sparse arrays"
+#endif
+ );
+
+ printf("arrays: %d = %d bytes\n", narrays, narrays*sizeof(struct sarray));
+ total += narrays*sizeof(struct sarray);
+ printf("buckets: %d = %d bytes\n", nbuckets, nbuckets*sizeof(struct sbucket));
+ total += nbuckets*sizeof(struct sbucket);
+
+ printf("idxtables: %d = %d bytes\n", idxsize, idxsize*sizeof(void*));
+ total += idxsize*sizeof(void*);
+ printf("-----------------------------------\n");
+ printf("total: %d bytes\n", total);
+ printf("===================================\n");
+}
+
+
+
diff --git a/gnu/usr.bin/cc/libobjc/typedstream.h b/gnu/usr.bin/cc/libobjc/typedstream.h
new file mode 100644
index 000000000000..1650bf55de6b
--- /dev/null
+++ b/gnu/usr.bin/cc/libobjc/typedstream.h
@@ -0,0 +1,132 @@
+/* GNU Objective-C Typed Streams interface.
+ Copyright (C) 1993 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU CC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* As a special exception, if you link this library with files compiled
+ with GCC to produce an executable, this does not cause the resulting
+ executable to be covered by the GNU General Public License. This
+ exception does not however invalidate any other reasons why the
+ executable file might be covered by the GNU General Public License. */
+
+#ifndef __typedstream_INCLUDE_GNU
+#define __typedstream_INCLUDE_GNU
+
+#include "objc/objc.h"
+#include "objc/hash.h"
+#include <stdio.h>
+
+#ifndef __alpha__ /* alpha is currently not supported */
+
+typedef int (*objc_typed_read_func)(void*, char*, int);
+typedef int (*objc_typed_write_func)(void*, const char*, int);
+typedef int (*objc_typed_flush_func)(void*);
+typedef int (*objc_typed_eof_func)(void*);
+
+#define OBJC_READONLY 0x01
+#define OBJC_WRITEONLY 0x02
+
+#define OBJC_MANAGED_STREAM 0x01
+#define OBJC_FILE_STREAM 0x02
+#define OBJC_MEMORY_STREAM 0x04
+
+#define OBJC_TYPED_STREAM_VERSION 0x01
+
+typedef struct objc_typed_stream {
+ void* physical;
+ cache_ptr object_table; /* read/written objects */
+ cache_ptr stream_table; /* other read/written but shared things.. */
+ cache_ptr class_table; /* class version mapping */
+ cache_ptr object_refs; /* forward references */
+ int mode; /* OBJC_READONLY or OBJC_WRITEONLY */
+ int type; /* MANAGED, FILE, MEMORY etc bit string */
+ int version; /* version used when writing */
+ int writing_root_p;
+ objc_typed_read_func read;
+ objc_typed_write_func write;
+ objc_typed_eof_func eof;
+ objc_typed_flush_func flush;
+} TypedStream;
+
+/* opcode masks */
+#define _B_VALUE 0x1fU
+#define _B_CODE 0xe0U
+#define _B_SIGN 0x10U
+#define _B_NUMBER 0x0fU
+
+/* standard opcodes */
+#define _B_INVALID 0x00U
+#define _B_SINT 0x20U
+#define _B_NINT 0x40U
+#define _B_SSTR 0x60U
+#define _B_NSTR 0x80U
+#define _B_RCOMM 0xa0U
+#define _B_UCOMM 0xc0U
+#define _B_EXT 0xe0U
+
+/* eXtension opcodes */
+#define _BX_OBJECT 0x00U
+#define _BX_CLASS 0x01U
+#define _BX_SEL 0x02U
+#define _BX_OBJREF 0x03U
+#define _BX_OBJROOT 0x04U
+#define _BX_EXT 0x1fU
+
+/*
+** Read and write objects as specified by TYPE. All the `last'
+** arguments are pointers to the objects to read/write.
+*/
+
+int objc_write_type (TypedStream* stream, const char* type, const void* data);
+int objc_read_type (TypedStream* stream, const char* type, void* data);
+
+int objc_write_types (TypedStream* stream, const char* type, ...);
+int objc_read_types (TypedStream* stream, const char* type, ...);
+
+int objc_write_object_reference (TypedStream* stream, id object);
+int objc_write_root_object (TypedStream* stream, id object);
+
+int objc_get_stream_class_version (TypedStream* stream, Class* class);
+
+
+/*
+** Convenience funtions
+*/
+
+int objc_write_array (TypedStream* stream, const char* type,
+ int count, const void* data);
+int objc_read_array (TypedStream* stream, const char* type,
+ int count, void* data);
+
+int objc_write_object (TypedStream* stream, id object);
+
+/*
+** Open a typed stream for reading or writing. MODE may be either of
+** OBJC_READONLY or OBJC_WRITEONLY.
+*/
+
+TypedStream* objc_open_typed_stream (FILE* physical, int mode);
+TypedStream* objc_open_typed_stream_for_file (const char* file_name, int mode);
+
+void objc_close_typed_stream (TypedStream* stream);
+
+BOOL objc_end_of_typed_stream (TypedStream* stream);
+void objc_flush_typed_stream (TypedStream* stream);
+
+#endif /* __alpha__ */
+
+#endif /* not __typedstream_INCLUDE_GNU */