Initial revision

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@750 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Andrew McCallum 1996-01-22 23:22:11 +00:00
parent 2b5de0130d
commit 5503dfbb4a
29 changed files with 7122 additions and 0 deletions

8
.cvsignore Normal file
View file

@ -0,0 +1,8 @@
=*
COPYING COPYING.LIB INSTALL NEWS README TAGS TODO
Makefile configure
config.cache config.guess config.log config.status
.date .name .patch* .snap*

138
BULLETIN Normal file
View file

@ -0,0 +1,138 @@
* GNU Objective C Class Library
The GNU Objective C Class Library (libobjects) is a library of
general-purpose, non-graphical Objective C objects written by
R. Andrew McCallum and designed in the Smalltalk tradition. It
includes collection objects for maintaining groups of objects and C
types, byte streams for I/O to various destinations, coders for
formating objects and C types to byte streams, ports for network
packet transmission, remote object messaging support, pseudo-random
number generators, and time handling facilities.
* GNU Objective C Class Library
The GNU Objective C Class Library (libobjects) is a library of
general-purpose, non-graphical Objective C objects designed in the
Smalltalk tradition. It includes collection objects for maintaining
groups of objects and C types, byte streams for I/O to various
destinations, coders for formating objects and C types to byte
streams, ports for network packet transmission, remote object
messaging support, pseudo-random number generators, and time handling
facilities. It is being written by R. Andrew McCallum.
* GNU Objective C Class Library (libobjects)
R. Andrew McCallum is writing the GNU Objective C Class Library, a
library of general-purpose, non-graphical Objective C objects designed
in the Smalltalk tradition. It includes collection objects for
maintaining groups of objects and C types, byte streams for I/O to
various destinations, coders for formating objects and C types to byte
streams, ports for network packet transmission, remote object
messaging support, pseudo-random number generators, and time handling
facilities. It is being written by R. Andrew McCallum.
* GNU Objective C Class Library
The GNU Objective C Class Library (@code{libobjects}) is a library of
general-purpose, non-graphical Objective C objects written by
R. Andrew McCallum. It includes collection objects for maintaining
groups of objects and C types, streams for I/O to various
destinations, coders for formating objects and C types to streams,
ports for network packet transmission, distributed objects (remote
object messaging), pseudo-random number generators, and time handling
facilities. Contact @samp{mccallum@gnu.ai.mit.edu}.
* GNU Objective C Class Library
The GNU Objective C Class Library (libobjects) is a library of
general-purpose, non-graphical Objective C objects written by
R. Andrew McCallum. What `libg++' is to GNU's C++, `libobjects' is to
GNU's Objective C.
The library features collection objects for maintaining groups of
objects and C types, byte streams for I/O to various destinations,
coders for formating objects and C types to byte streams, ports for
network packet transmission, remote object messaging support,
pseudo-random number generators, and time handling facilities.
The heirarchy of collection objects are similar in spirit to
Smalltalk's collections. A deep inheritance heirarchy provides good
uniformity of access to members across different collection classes.
All collections can hold simple C types such as int's and floats, as
well as Objects. The collection classes include simple collections
(Set, Bag), collections with contents accessible by unordered keys
(Dictionary, MappedCollector), collections with ordered contents
(Array, LinkedList, BinaryTree, RBTree, SplayTree). There is also a
DelegatePool object that can forward messages it receives to an
arbitrary number of Delegates.
Stream objects provide a consistent interface for reading and writing
bytes. `StdioStream' objects work with files, file descriptors, FILE
pointers and pipes to/from executables. `MemoryStream' objects work
with memory buffers. There are methods for writing arbitrary n-length
buffers, newline-terminated lines, and printf-style formated strings.
Coders provide a formatted way of writing to Streams. After a coder
is initialized with a stream, the coder can encode/decode Objective C
objects and C types in an architecture-independent way. The currently
available concrete coder classes are `BinaryCoder', for reading and
writing a compact stream of illegible bytes, and `TextCoder', for
reading and writing human-readable text (which you can also process
with `perl', `awk', or whatever scripting language you like).
Coders and streams can be mixed and matched so that programmers can
choose the destination and the format separately.
The current version is 0.1, the low number indicating that the library
is still in flux. Future version will include String objects and
before allocation/dealocation conventions.
see ~rms/gnuorg/status
Here is the simple description:
* GNU Objective C Class Library
The GNU Objective C Class Library (@code{libobjects}) is a library of
general-purpose, non-graphical Objective C objects written by
R. Andrew McCallum. It includes collection objects for maintaining
groups of objects and C types, streams for I/O to various
destinations, coders for formating objects and C types to streams,
ports for network packet transmission, distributed objects (remote
object messaging), pseudo-random number generators, and time handling
facilities. It is known to work on i386, m68k, SPARC, MIPS, and
RS6000. Contact the author at @samp{mccallum@gnu.ai.mit.edu}.
(GNU's Flashes)
* New Library (on the Languages Tape?)
The GNU Objective C Class Library (@code{libobjects}) has been added.
See ``GNU Software'' and ``Forthcoming GNUs'' for more information.
(Forthcoming GNUs)
* GNU Objective C Class Library
Future versions will have String objects that are integrated into the
Collection object hierarchy, a better allocation/deallocation
mechanism, improved features for distributed objects (including a
back-end that uses Mach ports instead of sockets), more extensive
random number generator facilities, and ports to more machines.
Volunteers are needed for additional projects; contact
@code{mccallum@gnu.ai.mit.edu}.

3196
ChangeLog Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1 @@
stdobjects.h

View file

@ -0,0 +1,53 @@
/* Interface for relase pools for delayed disposal
Copyright (C) 1994 Free Software Foundation, Inc.
Written by: R. Andrew McCallum <mccallum@gnu.ai.mit.edu>
Date: May 1993
This file is part of the GNU Objective C Class Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __AutoreleasePool_m_OBJECTS_INCLUDE
#define __AutoreleasePool_m_OBJECTS_INCLUDE
#include <objects/stdobjects.h>
#include <objects/ObjectRetaining.h>
@interface AutoreleasePool : Object
{
AutoreleasePool *parent;
unsigned released_count;
unsigned released_size;
id *released;
}
+ currentPool;
+ (void) autoreleaseObject: anObj;
- (void) autoreleaseObject: anObj;
- init;
@end
@interface Object (Retaining) <Retaining>
@end
void objc_retain_object (id anObj);
void objc_release_object (id anObj);
unsigned objc_retain_count (id anObj);
#endif /* __AutoreleasePool_m_OBJECTS_INCLUDE */

View file

@ -0,0 +1,122 @@
/* Interface to release stack for delayed disposal
Copyright (C) 1994 Free Software Foundation, Inc.
Written by: R. Andrew McCallum <mccallum@gnu.ai.mit.edu>
Date: May 1993
This file is part of the GNU Objective C Class Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __AutoreleaseStack_m_OBJECTS_INCLUDE
#define __AutoreleaseStack_m_OBJECTS_INCLUDE
#include <objects/stdobjects.h>
#include <objects/ObjectRetaining.h>
@interface AutoreleaseStack : Object
{
}
+ (void) autoreleaseObject: anObj;
- (void) autoreleaseObject: anObj;
- init;
@end
void objc_release_stack_objects();
/*
Use of this autorelease class gives -autorelease the following semantics:
- autorelease;
Use this message when the sender is done with this object, but the
sender doesn't want the object to be deallocated immediately
because the function that sends this message will use this object
as its return value. The object will be queued to receive the
actual "release" message only after the caller's caller returns.
(Well, not "queued", "stacked" actually.)
Due to this delayed release, the function that receives the object
as a return value will have the opportunity to retain the object
before the "release" instigated by the "autorelease" actually
takes place.
IMPORTANT PROGRAMMING CONVENTION: Since a autoreleased object may
be freed in the caller's caller's frame, a function must be careful
when returning an object that has been been autoreleased to it
(i.e. returning the object to the autorelease caller's caller's
caller). Since you cannot always know which objects returned to
the current function have been autoreleased by their returners,
you must use the following rule to insure safety for these
situations:
When returning an object that has been allocated, copied or
retained by the returner, return the object as usual. If
returning an object that has been received in this function by
another function, always retain and autorelease the object
before returning it. (Unless, of course, the returner still
needs to keep a reference to the object, in which case the final
autorelease should be omitted.)
The autorelease mechanism works as follows: The implementation of
the "autorelease" method pushes the receiver and the caller's
caller's frame address onto an internally maintained stack. But,
before pushing the reciever, the implementation checks the entries
already on the stack, popping elements off the stack until the
recorded frame address is less than the caller's caller's frame
address. Each object popped off the stack is sent a "release"
message. The stack capacity grows automatically if necessary.
This mechanism ensures that not too many autoreleased objects can
be stacked before we check to see what objects can be released
(i.e. no objects). It also ensures that objects which have been
autoreleased are released as soon as we autorelease any other
object in a lower stack frame.
The only way to build up an unnecessarily large collection of
autoreleased objects is by calling functions that autorelease an
object, and by repeatedly calling those functions from functions
with equal or increasingly higher frame addresses.
Any time that you suspect that you may be creating an unnecessarily
large number of autoreleased objects in a function, (e.g. the
function contains a loop that creates many autoreleased objects
that the function doesn't need), you can always release all the
releasable autoreleased objects for this frame by calling
objc_release_stack_objects(). Be warned that calling this function
will release all objects that have been autoreleased to this
function; if you still need to use some of them, you will have to
retain them beforehand, and release or autorelease them
afterwards.
If desired, you can also use objc_release_stack_objects() at the
top of an event loop, a guaranteed "catch-all" coding practise
similar to the creation and destruction of AutoreleasePool objects
in the event loop.
As an alternative to calling objc_release_stack_objects() you can
also use the same scheme for forcing autorelease's as used for
AutoreleasePool's: s = [[AutoreleaseStack alloc] init], ... code
that autoreleases a bunch of objects to the same stack level ...,
[s release]. It has the same effect.
*/
#endif /* __AutoreleaseStack_m_OBJECTS_INCLUDE */

View file

@ -0,0 +1,39 @@
/* Interface for Objective-C efficient small integers
Copyright (C) 1993,1994 Free Software Foundation, Inc.
Written by: R. Andrew McCallum <mccallum@gnu.ai.mit.edu>
Created: Sep 1995
This file is part of the GNU Objective C Class Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __SmallInt_h_INCLUDE_GNU
#define __SmallInt_h_INCLUDE_GNU
#include <objects/stdobjects.h>
#define IS_SMALLINT(OBJ) (((void*)OBJ) & 0x1)
#define ID2INT(OBJ) ((IS_SMALLINT(OBJ)) ? (((int)OBJ) >> 1):[OBJ intValue])
#define INT2ID(I) ((id)((I << 1) & 0x1))
@interface SmallInt : NSObject
-
@end
#endif /* __SmallInt_h_INCLUDE_GNU */

3
Makefile.local Normal file
View file

@ -0,0 +1,3 @@
install-lib: libobjects.a
$(INSTALL_DATA) libobjects.a $(libdir)/libobjects.a
$(RANLIB) $(libdir)/libobjects.a

52
README.ULTRIX Normal file
View file

@ -0,0 +1,52 @@
To: mccallum@cs.rochester.edu
Subject: Re: Connection, Proxy Classes
In-reply-to: Your message of "Fri, 04 Nov 1994 15:22:27 CDT."
<199411042022.PAA13085@slate.cs.rochester.edu>
Date: Tue, 08 Nov 1994 12:44:07 +1100
From: Masahiro Takatsuka <masa@judasa2.eng.monash.edu.au>
Hello Andrew,
I got libobjects and installed on DEC(Ultrix).
A problem was that when I tried to compile checks/server.m, I
got a error from "as0". After delete -g switch for compiling
server.m, I successfully compiled it.
I'd like to say "Thank you" for your work!!!
Regards,
Masa
============================================================================
Masahiro Takatsuka (MASA)
e-mail: Masahiro.Takatsuka@eng.monash.edu.au(non-NeXTmail)
----------------------------------------------------------------------------
Intelligent Robotics Research Center :OzNeXT :xxxxxx
Eng. Building 36, Room No. G04 :NeXus :92-00226
Department of Electrical & :CompuServe :71661,1331
Computer Systems Engineering :Nifty-serve :MGG1331
Monash University :
Wellington Rd., Clayton :Tel.+61-3-905-5705
Victoria 3168, AUSTRALIA :Fax.+61-3-905-3454
============================================================================
Date: Mon, 9 Jan 1995 14:03:21 -0700 (MST)
From: Adam Fedor <fedor@mode.Colorado.EDU>
Subject: Re: libobjects porting volunteers needed
To: mccallum@cs.rochester.edu
In-Reply-To: <199501092051.PAA06062@slate.cs.rochester.edu>
Message-Id: <Pine.3.89.9501091354.C20349-0100000@mode.Colorado.EDU>
Mime-Version: 1.0
Content-Type: TEXT/PLAIN; charset=US-ASCII
On Mon, 9 Jan 1995 mccallum@cs.rochester.edu wrote:
>
> Did you look at README.ULTRIX in 0.1.2?
>
Yes. I also forgot to say that deleting the -g switch didn't help me,
but deleting the -O switch did. Without this, I get the error:
as0: Internal: server.m, line 1: scNil to scNil

26
README.first Normal file
View file

@ -0,0 +1,26 @@
This is a snapshot distribution of libobjects.
It is a totally untested "snapshot" of the source tree made on the
date indicated by the filename.
This release is not intended for casual users of libobjects---it is
meant for libobjects developers.
IMPORTANT:
This means that naive users should *not* send me email complaining
that something in this snapshot doesn't work. Preferred responses
to problems with this snapshot are:
1) Fix the problem yourself and email me a patch. (See the message
about the preferred format for patches in admin/HOWTO-patches.)
2) Find the problem and email a detailed description to the author of
the relevant file.
3) Don't use this snapshot; switch to the officially released version
of libobjects at ftp://prep.ai.mit.edu/pub/gnu.
Andrew McCallum
mccallum@gnu.ai.mit.edu

189
Source/MachPort.m Normal file
View file

@ -0,0 +1,189 @@
/* Implementation of Machport-based port object for use with Connection
Copyright (C) 1994 Free Software Foundation, Inc.
Written by: R. Andrew McCallum <mccallum@gnu.ai.mit.edu>
Date: September 1994
This file is part of the GNU Objective C Class Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <objects/MachPort.h>
#include <objects/Connection.h>
#include <objects/Lock.h>
#include <objects/Set.h>
#include <objc/hash.h>
#include <mach/cthreads.h>
#include <mach/notify.h>
static Dictionary *portDictionary;
static Lock *portDictionaryGate;
@implementation MachPort
+ initialize
{
portDictionaryGate = [Lock new];
assert(sizeof(int) == sizeof(port_t));
portDictionary = [[Dictionary alloc]
initWithType:@encode(id)
keyType:@encode(int)];
return self;
}
/* This not tested */
static int
worry (any_t arg)
{
kern_return_t r;
notification_t m;
m.notify_header.msg_size = sizeof(notification_t);
m.notify_header.msg_local_port = task_notify();
for (;;)
{
r = msg_receive((msg_header_t*)&m, MSG_OPTION_NONE, 0);
switch (r)
{
case RCV_SUCCESS:
fprintf(stderr, "notification id %d\n", (int)m.notify_header.msg_id);
break;
case RCV_TIMED_OUT:
fprintf(stderr, "notification msg_receive timed out\n");
exit(-1);
default:
mach_error("notification", r);
exit(-1);
}
switch (m.notify_header.msg_id)
{
case NOTIFY_PORT_DELETED:
[[MachPort newFromMachPort:m.notify_port] invalidate];
break;
case NOTIFY_MSG_ACCEPTED:
break;
case NOTIFY_PORT_DESTROYED:
[[MachPort newFromMachPort:m.notify_port] invalidate];
break;
default:
mach_error("notification", r);
exit(-1);
}
/* Where do we free the object? */
}
return 0;
}
/* This not tested */
+ worryAboutPortInvalidation
{
MachPort *worryPort = [MachPort new];
task_set_special_port(task_self(), TASK_NOTIFY_PORT, [worryPort machPort]);
cthread_detach(cthread_fork((any_t)worry, (any_t)0));
return self;
}
/* designated initializer */
+ newFromMachPort: (port_t)p dealloc: (BOOL)f
{
MachPort *aPort;
[portDictionaryGate lock];
if ((aPort = [portDictionary elementAtKey:(int)p]))
{
[portDictionaryGate unlock];
[aPort addReference];
return aPort;
}
aPort = [[self alloc] init];
aPort->machPort = p;
aPort->deallocate = f;
[portDictionary addElement:aPort atKey:(int)p];
[portDictionaryGate unlock];
return aPort;
}
+ newFromMachPort: (port_t)p
{
return [self newFromMachPort:p dealloc:NO];
}
+ new
{
kern_return_t error;
port_t p;
if ((error=port_allocate(task_self(), &p)) != KERN_SUCCESS) {
mach_error("port_allocate failed", error);
exit(1);
}
return [self newFromMachPort:p];
}
- encodeUsing: aPortal
{
[aPortal encodeData:&deallocate ofType:@encode(BOOL)];
[aPortal encodeMachPort:machPort];
return self;
}
- decodeUsing: aPortal
{
BOOL f;
port_t mp;
MachPort *p;
[aPortal decodeData:&f ofType:@encode(BOOL)];
[aPortal decodeMachPort:&mp];
/* Is this right? Can we return a different object than 'self' */
p = [MachPort newFromMachPort:mp dealloc:f];
[self release];
return p;
}
- (unsigned) hash
{
/* What should this be? */
return (unsigned)self;
}
- (void) dealloc
{
if (refcount-1 == 0)
{
[portDictionaryGate lock];
[portDictionaryGate removeElementAtKey:(int)machPort];
[portDictionaryGate unlock];
if (deallocate)
{
kern_return_t error;
error = port_deallocate(task_self(), machPort);
if (error != KERN_SUCCESS) {
mach_error("port_deallocate failed", error);
exit(1);
}
}
}
[super dealloc];
return self;
}
- (port_t) machPort
{
return machPort;
}
@end

0
Source/Makefile.local Normal file
View file

135
Source/MethodSignature.m Normal file
View file

@ -0,0 +1,135 @@
#include <remote/MethodSignature.h>
static int
types_get_size_of_arguments(const char *types)
{
const char* type = objc_skip_typespec (types);
return atoi (type);
}
static int
types_get_number_of_arguments (const char *types)
{
int i = 0;
const char* type = types;
while (*type)
{
type = objc_skip_argspec (type);
i += 1;
}
return i - 1;
}
@implementation MethodSignature
+ fromDescription:(struct objc_method_description *)omd
fromZone:(NXZone *)aZone
{
MethodSignature *newMs = [[MethodSignature alloc] init];
newMs->sig = *omd;
newMs->selName = (char*)sel_get_name(omd->name);
newMs->nargs = types_get_number_of_arguments(omd->types);
newMs->sizeofParams = types_get_size_of_arguments(omd->types);
return newMs;
}
- encodeMethodParams:(arglist_t)argFrame onto:(id <NXEncoding>)portal
{
char *datum;
const char *type;
unsigned flags;
for (type = sig.types;
(datum = method_get_next_argument(argFrame, &type));)
{
flags = objc_get_type_qualifiers(type);
type = objc_skip_type_qualifiers(type);
[portal encodeData:datum ofType:type];
}
return self;
}
- (arglist_t) decodeMethodParamsFrom: (id <NXDecoding>)portal
{
arglist_t argFrame = 0; //(marg_list) malloc(sizeofParams);
char *datum;
const char *type;
unsigned flags;
for (type = sig.types;
(datum = method_get_next_argument(argFrame, &type));)
{
flags = objc_get_type_qualifiers(type);
type = objc_skip_type_qualifiers(type);
[portal decodeData:datum ofType:type];
}
return argFrame;
}
#define ENCODE_RET(RETVAL,TYPE) \
do { \
TYPE __r (void* __rf) {__builtin_return(__rf);} \
TYPE __tmp = __r(RETVAL); \
[portal encodeData:&__tmp ofType:sig.types]; \
} while(0);
/* Note: NeXT's direct passing of the ret value instead of a
pointer to the ret value means we can't return doubles.
I'm improving on this by passing a pointer what's
returns from __builtin_apply() */
- encodeMethodRet: retframe
withargs:(void *)argFrame
onto:(id <NXEncoding>)portal
{
/* NOTE: we don't yet handle changing values passed by reference */
switch (*sig.types)
{
case _C_CHR:
case _C_UCHR:
ENCODE_RET(retframe, char);
break;
case _C_SHT:
case _C_USHT:
ENCODE_RET(retframe, short);
break;
case _C_INT:
case _C_UINT:
ENCODE_RET(retframe, int);
break;
case _C_LNG:
case _C_ULNG:
ENCODE_RET(retframe, int);
break;
case _C_FLT:
ENCODE_RET(retframe, float);
break;
case _C_DBL:
ENCODE_RET(retframe, double);
break;
default:
[self error:"Can't handle type %s", sig.types];
}
return self;
}
/* In my version this actually returns the void* to be given to
__builtin_return. I'm not sure what NeXT's version does */
- decodeMethodRetFrom:(id <NXDecoding>)portal
withargs:(void *)aVoidPtr
{
//#warning this should be sizeof return
void *datum = malloc(32); /* this should be sizeof return */
[portal decodeData:datum ofType:sig.types];
return datum;
}
- (BOOL) isOneway
{
return NO;
}
@end

42
Source/NSLog.m Normal file
View file

@ -0,0 +1,42 @@
/* Implementation of NSLog() error loging functions for GNUStep
Copyright (C) 1995 Free Software Foundation, Inc.
Written by: R. Andrew McCallum <mccallum@gnu.ai.mit.edu>
Created: Nov 1995
This file is part of the GNU Objective C Class Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
`void NSLog(NSString *format,...'
) Writes to stderr an error message of the form:
ª \i time processName processID format\i0 º. The format argument
to `NSLog()' is a format string in the style of the standard C
function `printf()', followed by an arbitrary number of arguments
that match conversion specifications (such as %s or %d) in the
format string. (You can pass an object in the list of arguments by
specifying % in the format stringÐthis conversion specification
gets replaced by the string that the object's description method
returns.)
void
NSLogv(NSString* format, va_list args)
{
fprintf(stderr, "", );
vfprintf(stderr, [[NSString stringWithFormat:format
arguments:args] cString]);
}

43
Source/ProtocolEnforcer.m Normal file
View file

@ -0,0 +1,43 @@
@interface ProtocolEnforcer
{
id target;
Protocol *protocol;
}
- initWithProtocol: aProtocol target: anObj;
- (BOOL) conformsTo: aProtocol;
- forward: (SEL)sel :(arglist_t)frame;
@end
@implementation ProtocolEnforcer
- initWithProtocol: aProtocol target: anObj
{
[super init];
protocol = aProtocol;
target = anObj;
return self;
}
- (BOOL) conformsTo: aProtocol
{
if (aProtocol == protocol)
return YES;
else
return NO;
}
- (retval_t) forward: (SEL)sel :(arglist_t)frame
{
if ([protocol descriptionForInstanceMethod:sel])
return [target performv:sel :frame];
else
#warning Fix this
return
[self error:"We should punish the remote connection not the local one"];
}
@end

76
Source/ReleasePool.m Normal file
View file

@ -0,0 +1,76 @@
static unsigned released_capacity = 0;
static unsigned released_index = 0;
static id *released_objects = NULL;
static void **released_stack_pointers = NULL;
#define DEFAULT_SIZE 64
static void *s1, *s2;
static void unsigned stack_release_offset;
static void init_stack_release()
{
s1 = get_stack();
[Object _stackReleaseTest];
stack_release_offset = s2 - s1;
released_capacity = DEFAULT_SIZE;
OBJC_MALLOC(released_objects, id, released_capacity);
OBJC_MALLOC(released_stack_pointers, void*, released_capacity);
}
static void*
get_stack()
{
int i;
return &i;
}
static inline void
grow_released_arrays()
{
if (index == released_capacity)
{
released_capacity *= 2;
OBJC_REALLOC(released_objects, id, released_capacity);
OBJC_REALLOC(released_stack_pointers, void*, released_capacity);
}
}
@implementation Object (Releasing)
+ _stackReleaseTest
{
s2 = get_stack();
}
- stackRelease
/* - releaseLater */
{
static init_done = 0;
/* Initialize if we haven't done it yet */
if (!init_done)
{
init_stack_release();
init_done = 1;
}
/* Do the pending releases of other objects */
/* xxx This assumes stack grows up */
while ((released_stack_pointers[released_index]
> (get_stack() - stack_release_offset))
&& released_index)
{
[released_objects[released_index] release];
released_index--;
}
/* Queue this object for later release */
released_index++;
grow_released_arrays();
released_objects[released_index] = self;
return self;
}
@end

5
Source/Ring.m Normal file
View file

@ -0,0 +1,5 @@
/* Ring.m - a fixed-length circular array */
@implementation Ring
@end

97
Source/SunRpcPort.m Normal file
View file

@ -0,0 +1,97 @@
#include <objects/Port.h>
#include <rpc/rpc.h>
@interface SunRpcPort : Port
{
}
@end
@implementation SunRpcPort
+ newRegisteredPortWithName: (const char *)n
{
SunRpcPort *newPort;
unsigned long prognum, versnum, procnum;
char *(*procname)();
xdrproc_t *(*procname)();
if (registerrpc(prognum, versnum, procnum, procname, inproc, outproc))
[self error:"registerrpc failed"];
return newPort;
}
+ newPortFromRegisterWithName: (const char *)n onHost: (const char *)host
{
[self notImplemented:_cmd];
return nil;
}
+ newPort
{
[self notImplemented:_cmd];
return nil;
}
/* These sending and receiving interfaces will change */
- (int) sendPacket: (const char *)b length: (int)l
toPort: (Port*) remote
timeout: (int) milliseconds
{
[self notImplemented:_cmd];
return 0;
}
- (int) sendPacket: (const char *)b length: (int)l
toPort: (Port*) remote
{
return [self sendPacket:b length:l toPort:remote timeout:-1];
}
- (int) receivePacket: (char*)b length: (int)l
fromPort: (Port**) remote
timeout: (int) milliseconds
{
[self notImplemented:_cmd];
return 0;
}
- (int) receivePacket: (char*)b length: (int)l
fromPort: (Port**) remote
{
return [self receivePacket:b length:l fromPort:remote timeout:-1];
}
- (BOOL) canReceive
{
[self notImplemented:_cmd];
return NO;
}
- (BOOL) isEqual: anotherPort
{
[self notImplemented:_cmd];
return NO;
}
- (unsigned) hash
{
[self notImplemented:_cmd];
return 0;
}
- (void) encodeWithCoder: (Coder*)anEncoder
{
[self notImplemented:_cmd];
}
+ newWithCoder: (Coder*)aDecoder;
{
[self notImplemented:_cmd];
return 0;
}
@end

15
Source/Thread.m Normal file
View file

@ -0,0 +1,15 @@
#if defined(NeXT)
#elif defined(MACH)
#elif defined(sun) && defined(svr4)
@implementation Thread
@end
@implementation Lock
@end
#else
#error Threads not available for this system.
#endif

476
Source/Tree.m Normal file
View file

@ -0,0 +1,476 @@
/* Implementation for Objective-C Tree collection object
Copyright (C) 1993,1994, 1995 Free Software Foundation, Inc.
Written by: R. Andrew McCallum <mccallum@gnu.ai.mit.edu>
Date: May 1993
This file is part of the GNU Objective C Class Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <objects/Tree.h>
#include <objects/IndexedCollectionPrivate.h>
#include <objects/TreeNode.h>
/* sentinal */
static id nilTreeNode;
@implementation Tree
+ initialize
{
if (self == [Tree class])
{
[self setVersion:0]; /* beta release */
nilTreeNode = [[TreeNode alloc] init];
}
return self;
}
/* This is the designated initializer of this class */
- init
{
[super initWithType:@encode(id)];
_count = 0;
_contents_root = [self nilNode];
return self;
}
/* Archiving must mimic the above designated initializer */
- _newCollectionWithCoder: aCoder
{
[super _initCollectionWithCoder:aCoder];
_count = 0;
_contents_root = [self nilNode];
return self;
}
- (void) _encodeContentsWithCoder: (Coder*)aCoder
{
[aCoder startEncodingInterconnectedObjects];
[super _encodeContentsWithCoder:aCoder];
[aCoder finishEncodingInterconnectedObjects];
}
- (void) _decodeContentsWithCoder: (Coder*)aCoder
{
[aCoder startDecodingInterconnectedObjects];
[super _decodeContentsWithCoder:aCoder];
[aCoder finishDecodingInterconnectedObjects];
}
/* Empty copy must empty an allocCopy'ed version of self */
- emptyCopy
{
Tree *copy = [super emptyCopy];
copy->_count = 0;
copy->_contents_root = [self nilNode];
return copy;
}
/* This must work without sending any messages to content objects */
- _empty
{
_count = 0;
_contents_root = [self nilNode];
return self;
}
/* Override the designated initializer for our superclass IndexedCollection
to make sure we have object contents */
- initWithType: (const char *)contentEncoding
{
if (!ENCODING_IS_OBJECT(contentEncoding))
[self error:"Tree contents must be objects."];
return [self init];
}
- nilNode
{
return nilTreeNode;
}
- rootNode
{
return _contents_root;
}
- leftmostNodeFromNode: aNode
{
id left;
if (aNode && aNode != [self nilNode])
{
while ([[aNode children] count] &&
(left = [[aNode children] firstObject]) != [self nilNode])
aNode = left;
}
return aNode;
}
- rightmostNodeFromNode: aNode
{
id right;
if (aNode && aNode != [self nilNode])
while ([[aNode children] count] &&
(right = [[aNode children] lastObject]) != [self nilNode])
{
aNode = right;
}
return aNode;
}
- (elt) firstElement
{
return [self leftmostNodeFromNode:_contents_root];
}
- (elt) lastElement
{
return [self rightmostNodeFromNode:_contents_root];
}
/* This is correct only is the tree is sorted. How to deal with this? */
- (elt) maxElement
{
return [self rightmostNodeFromNode:_contents_root];
}
/* This is correct only is the tree is sorted. How to deal with this? */
- (elt) minElement
{
return [self leftmostNodeFromNode:_contents_root];
}
// returns [self nilNode] is there is no successor;
- (elt) successorOfElement: (elt)anElement
{
id tmp;
// here tmp is the right node;
if ((tmp = [anElement.id_u rightNode]) != [self nilNode])
return [self leftmostNodeFromNode:tmp];
// here tmp is the parent;
tmp = [anElement.id_u parentNode];
while (tmp != [self nilNode]
[[tmp children] count] &&
&& anElement.id_u == [[tmp children] lastObject])
{
anElement.id_u = tmp;
tmp = [tmp parentNode];
}
return tmp;
}
// I should make sure that [_contents_root parentNode] == [self nilNode];
// Perhaps I should make [_contents_root parentNode] == TreeObj ??;
// returns [self nilNode] is there is no predecessor;
- (elt) predecessorElement: (elt)anElement
{
id tmp;
// here tmp is the left node;
if ((tmp = [anElement.id_u leftNode]) != [self nilNode])
return [self rightmostNodeFromNode:tmp];
// here tmp is the parent;
tmp = [anElement.id_u parentNode];
while (tmp != [self nilNode]
[[tmp children] count] &&
&& anElement.id_u == [[tmp children] firstObject])
{
anElement.id_u = tmp;
tmp = [tmp parentNode];
}
return tmp;
}
/* This relies on [_contents_root parentNode] == [self nilNode] */
- rootFromNode: aNode
{
id parentNode;
while ((parentNode = [aNode parentNode]) != [self nilNode])
aNode = parentNode;
return aNode;
}
/* This relies on [_contents_root parentNode] == [self nilNode] */
- (unsigned) depthOfNode: aNode
{
unsigned count = 0;
if (aNode == nil || aNode == [self nilNode])
[self error:"in %s, Can't find depth of nil node", sel_get_name(_cmd)];
do
{
aNode = [aNode parentNode];
count++;
}
while (aNode != [self nilNode]);
return count;
}
#if 0
- (unsigned) heightOfNode: aNode
{
unsigned leftHeight, rightHeight;
id tmpNode;
if (aNode == nil || aNode == [self nilNode])
{
[self error:"in %s, Can't find height of nil node", sel_get_name(_cmd)];
return 0;
}
else
{
leftHeight = ((tmpNode = [aNode leftNode])
?
(1 + [self heightOfNode:tmpNode])
:
0);
rightHeight = ((tmpNode = [aNode rightNode])
?
(1 + [self heightOfNode:tmpNode])
:
0);
return MAX(leftHeight, rightHeight);
}
}
- (unsigned) nodeCountUnderNode: aNode
{
unsigned count = 0;
if ([aNode leftNode] != [self nilNode])
count += 1 + [self nodeCountUnderNode:[aNode leftNode]];
if ([aNode rightNode] != [self nilNode])
count += 1 + [self nodeCountUnderNode:[aNode rightNode]];
return count;
}
#endif
- (elt) elementAtIndex: (unsigned)index
{
elt ret;
CHECK_INDEX_RANGE_ERROR(index, _count);
ret = [self firstElement];
// Not very efficient; Should be rewritten;
while (index--)
ret = [self successorOfElement:ret];
return ret;
}
#if 0
- sortAddElement: (elt)newElement byCalling: (int(*)(elt,elt))aFunc
{
id theParent, tmpChild;
[newElement.id_u setLeftNode:[self nilNode]];
[newElement.id_u setRightNode:[self nilNode]];
theParent = [self nilNode];
tmpChild = _contents_root;
while (tmpChild != [self nilNode])
{
theParent = tmpChild;
if ((*aFunc)(newElement,theParent) < 0)
tmpChild = [tmpChild leftNode];
else
tmpChild = [tmpChild rightNode];
}
[newElement.id_u setParentNode:theParent];
if (theParent == [self nilNode])
_contents_root = newElement.id_u;
else
{
if (COMPARE_ELEMENTS(newElement, theParent) < 0)
[theParent setLeftNode:newElement.id_u];
else
[theParent setRightNode:newElement.id_u];
}
_count++;
return self;
}
#endif
- addElement: (elt)newElement
{
// By default add to root node. Is this what we want?;
if (_contents_root)
[[_contents_root children] addObject:newElement.id_u];
else
_contents_root = newElement.id_u;
_count++;
return self;
}
#if 0
// NOTE: This gives you the power to put elements in unsorted order;
- insertElement: (elt)newElement before: (elt)oldElement
{
id tmp;
#ifdef SAFE_Tree
if ([self rootFromNode:oldElement.id_u] != _contents_root)
[self error:"in %s, oldElement not in tree!!", sel_get_name(_cmd)];
#endif
[newElement.id_u setRightNode:[self nilNode]];
[newElement.id_u setLeftNode:[self nilNode]];
if ((tmp = [oldElement.id_u leftNode]) != [self nilNode])
{
[(tmp = [self rightmostNodeFromNode:tmp]) setRightNode:newElement.id_u];
[newElement.id_u setParentNode:tmp];
}
else if (newElement.id_u != [self nilNode])
{
[oldElement.id_u setLeftNode:newElement.id_u];
[newElement.id_u setParentNode:oldElement.id_u];
}
else
{
_contents_root = newElement.id_u;
[newElement.id_u setParentNode:[self nilNode]];
}
_count++;
return self;
}
// NOTE: This gives you the power to put elements in unsorted order;
- insertElement: (elt)newElement after: (elt)oldElement
{
id tmp;
#ifdef SAFE_Tree
if ([self rootFromNode:oldElement.id_u] != _contents_root)
[self error:"in %s, !!!!!!!!", sel_get_name(_cmd)];
#endif
[newElement.id_u setRightNode:[self nilNode]];
[newElement.id_u setLeftNode:[self nilNode]];
if ((tmp = [oldElement.id_u rightNode]) != [self nilNode])
{
[(tmp = [self leftmostNodeFromNode:tmp]) setLeftNode:newElement.id_u];
[newElement.id_u setParentNode:tmp];
}
else if (newElement.id_u != [self nilNode])
{
[oldElement.id_u setRightNode:newElement.id_u];
[newElement.id_u setParentNode:oldElement.id_u];
}
else
{
_contents_root = newElement.id_u;
[newElement.id_u setParentNode:[self nilNode]];
}
_count++;
return self;
}
// NOTE: This gives you the power to put elements in unsorted order;
- insertElement: (elt)newElement atIndex: (unsigned)index
{
CHECK_INDEX_RANGE_ERROR(index, _count+1);
if (index == _count)
[self appendElement:newElement];
else
[self insertElement:newElement before:[self elementAtIndex:index]];
return self;
}
// NOTE: This gives you the power to put elements in unsorted order;
- appendElement: (elt)newElement
{
if (_count == 0)
{
_contents_root = newElement.id_u;
_count = 1;
[newElement.id_u setLeftNode:[self nilNode]];
[newElement.id_u setRightNode:[self nilNode]];
[newElement.id_u setParentNode:[self nilNode]];
}
else
[self insertElement:newElement after:[self lastElement]];
return self;
}
#endif
- (elt) removeElement: (elt)oldElement
{
id parent = [oldElement.id_u parentNode];
[parent removeObject:oldElement.id_u];
[parent addContentsOf:[oldElement.id_u children]];
_count--;
return oldElement;
}
- withElementsCall: (void(*)(elt))aFunc whileTrue: (BOOL*)flag
{
void traverse(id aNode)
{
if (!(*flag) || aNode == [self nilNode] || !aNode)
return;
(*aFunc)(aNode);
[[aNode children] withObjectsCall:traverse];
}
traverse(_contents_root);
return self;
}
- withElementsInReverseCall: (void(*)(elt))aFunc whileTrue: (BOOL*)flag
{
void traverse(id aNode)
{
if (*flag || aNode == [self nilNode] || !aNode)
return;
[[aNode children] withObjectsCall:traverse];
(*aFunc)(aNode);
}
traverse(_contents_root);
return self;
}
- (BOOL) getNextElement:(elt *)anElementPtr withEnumState: (void**)enumState
{
if (!(*enumState))
*enumState = [self leftmostNodeFromNode:_contents_root];
else
*enumState = [self successorOfElement:*enumState].id_u;
*anElementPtr = *enumState;
if (*enumState)
return YES;
return NO;
}
- (BOOL) getPrevElement:(elt *)anElementPtr withEnumState: (void**)enumState
{
if (!(*enumState))
*enumState = [self rightmostNodeFromNode:_contents_root];
else
*enumState = [self predecessorElement:*enumState].id_u;
*anElementPtr = *enumState;
if (*enumState)
return YES;
return NO;
}
- (unsigned) count
{
return _count;
}
@end

97
Source/TreeNode.m Normal file
View file

@ -0,0 +1,97 @@
/* Implementation for Objective-C TreeNode object
Copyright (C) 1993,1994, 1995 Free Software Foundation, Inc.
Written by: R. Andrew McCallum <mccallum@gnu.ai.mit.edu>
Date: May 1993
This file is part of the GNU Objective C Class Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <objects/TreeNode.h>
#include <objects/Array.h>
@implementation TreeNode
+ initialize
{
if (self == [TreeNode class])
[self setVersion:0]; /* beta release */
return self;
}
+ defaultChildrenCollectionClass
{
return [Array class];
}
- initWithChildren: (id <Collecting>)kids
{
[super init];
_parent = [self nilNode];
_children = kids;
return self;
}
- init
{
[self initWithChildren:[[[self defaultChildrenCollectionClass] alloc] init]];
return self;
}
- (void) encodeWithCoder: aCoder
{
[super encodeWithCoder:aCoder];
[aCoder encodeObjectReference:_parent withName:"Parent Tree Node"];
[aCoder encodeObject:_children withName:"Children of Tree Node"];
}
- initWithCoder: aCoder
{
[self initWithCoder:aCoder];
[aCoder decodeObjectAt:&_parent withName:NULL];
[aCoder decodeObjectAt:&_children withName:NULL];
return n;
}
- children
{
return _children;
}
- parentNode
{
return _parent;
}
- (void) setChildren: (id <IndexedCollecting>)kids
{
/* xxx
[kids retain];
[_children release];
*/
_children = kids;
return self;
}
- (void) setParentNode: aNode
{
_parent = aNode;
return self;
}
@end

441
Source/gnu4next.m Normal file
View file

@ -0,0 +1,441 @@
/* Method encoding types for Objective C.
Copyright (C) 1993,1994 Free Software Foundation, Inc.
Author: Kresten Krab Thorup
Modified by: Andrew McCallum
This file is part of the GNU Objective C Class Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "objects/next2gnu.h"
#include <objc/objc.h>
#include <objc/objc-api.h>
/* Deal with strrchr: */
#if STDC_HEADERS || HAVE_STRING_H
#include <string.h>
/* An ANSI string.h and pre-ANSI memory.h might conflict. */
#if !STDC_HEADERS && HAVE_MEMORY_H
#include <memory.h>
#endif /* not STDC_HEADERS and HAVE_MEMORY_H */
#define index strchr
#define rindex strrchr
#define bcopy(s, d, n) memcpy ((d), (s), (n))
#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n))
#define bzero(s, n) memset ((s), 0, (n))
#else /* not STDC_HEADERS and not HAVE_STRING_H */
#include <strings.h>
/* memory.h and strings.h conflict on some systems. */
#endif /* not STDC_HEADERS and not HAVE_STRING_H */
#define MAX(X, Y) \
({ typeof(X) __x = (X), __y = (Y); \
(__x > __y ? __x : __y); })
#define MIN(X, Y) \
({ typeof(X) __x = (X), __y = (Y); \
(__x < __y ? __x : __y); })
#define ROUND(V, A) \
({ typeof(V) __v=(V); typeof(A) __a=(A); \
__a*((__v+__a-1)/__a); })
static inline int
atoi (const char* str)
{
int res = 0;
while (isdigit (*str))
res *= 10, res += (*str++ - '0');
return res;
}
#if NeXT_runtime
/*
return the size of an object specified by type
*/
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:
return sizeof(int);
break;
case _C_UINT:
return sizeof(unsigned int);
break;
case _C_LNG:
return sizeof(long);
break;
case _C_ULNG:
return sizeof(unsigned long);
break;
case _C_FLT:
return sizeof(float);
break;
case _C_DBL:
return sizeof(double);
break;
case _C_PTR:
case _C_ATOM:
case _C_CHARPTR:
return sizeof(char*);
break;
case _C_ARY_B:
{
int len = atoi(type+1);
while (isdigit(*++type));
return len*objc_aligned_size (type);
}
break;
case _C_STRUCT_B:
{
int acc_size = 0;
int align;
while (*type != _C_STRUCT_E && *type++ != '='); /* skip "<name>=" */
while (*type != _C_STRUCT_E)
{
align = objc_alignof_type (type); /* padd to alignment */
acc_size = ROUND (acc_size, align);
acc_size += objc_sizeof_type (type); /* add component size */
type = objc_skip_typespec (type); /* skip component */
}
return acc_size;
}
case _C_UNION_B:
{
int max_size = 0;
while (*type != _C_UNION_E && *type++ != '=') /* do nothing */;
while (*type != _C_UNION_E)
{
max_size = MAX (max_size, objc_sizeof_type (type));
type = objc_skip_typespec (type);
}
return max_size;
}
default:
abort();
}
}
/*
Return the alignment of an object specified by type
*/
int
objc_alignof_type(const char* type)
{
switch(*type) {
case _C_ID:
return __alignof__(id);
break;
case _C_CLASS:
return __alignof__(Class);
break;
case _C_SEL:
return __alignof__(SEL);
break;
case _C_CHR:
return __alignof__(char);
break;
case _C_UCHR:
return __alignof__(unsigned char);
break;
case _C_SHT:
return __alignof__(short);
break;
case _C_USHT:
return __alignof__(unsigned short);
break;
case _C_INT:
return __alignof__(int);
break;
case _C_UINT:
return __alignof__(unsigned int);
break;
case _C_LNG:
return __alignof__(long);
break;
case _C_ULNG:
return __alignof__(unsigned long);
break;
case _C_FLT:
return __alignof__(float);
break;
case _C_DBL:
return __alignof__(double);
break;
case _C_ATOM:
case _C_CHARPTR:
return __alignof__(char*);
break;
case _C_ARY_B:
while (isdigit(*++type)) /* do nothing */;
return objc_alignof_type (type);
case _C_STRUCT_B:
{
struct { int x; double y; } fooalign;
while(*type != _C_STRUCT_E && *type++ != '=') /* do nothing */;
if (*type != _C_STRUCT_E)
return MAX (objc_alignof_type (type), __alignof__ (fooalign));
else
return __alignof__ (fooalign);
}
case _C_UNION_B:
{
int maxalign = 0;
while (*type != _C_UNION_E && *type++ != '=') /* do nothing */;
while (*type != _C_UNION_E)
{
maxalign = MAX (maxalign, objc_alignof_type (type));
type = objc_skip_typespec (type);
}
return maxalign;
}
default:
abort();
}
}
/*
The aligned size if the size rounded up to the nearest alignment.
*/
int
objc_aligned_size (const char* type)
{
int size = objc_sizeof_type (type);
int align = objc_alignof_type (type);
return ROUND (size, align);
}
/*
The size rounded up to the nearest integral of the wordsize, taken
to be the size of a void*.
*/
int
objc_promoted_size (const char* type)
{
int size = objc_sizeof_type (type);
int wordsize = sizeof (void*);
return ROUND (size, wordsize);
}
/*
Skip type qualifiers. These may eventually precede typespecs
occuring in method prototype encodings.
*/
inline const char*
objc_skip_type_qualifiers (const char* type)
{
while (*type == _C_CONST
|| *type == _C_IN
|| *type == _C_INOUT
|| *type == _C_OUT
|| *type == _C_BYCOPY
|| *type == _C_ONEWAY)
{
type += 1;
}
return type;
}
/*
Skip one typespec element. If the typespec is prepended by type
qualifiers, these are skipped as well.
*/
const char*
objc_skip_typespec (const char* type)
{
type = objc_skip_type_qualifiers (type);
switch (*type) {
case _C_ID:
/* An id may be annotated by the actual type if it is known
with the @"ClassName" syntax */
if (*++type != '"')
return type;
else
{
while (*++type != '"') /* do nothing */;
return type + 1;
}
/* The following are one character type codes */
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:
case _C_VOID:
return ++type;
break;
case _C_ARY_B:
/* skip digits, typespec and closing ']' */
while(isdigit(*++type));
type = objc_skip_typespec(type);
if (*type == _C_ARY_E)
return ++type;
else
abort();
case _C_STRUCT_B:
/* skip name, and elements until closing '}' */
while (*type != _C_STRUCT_E && *type++ != '=');
while (*type != _C_STRUCT_E) { type = objc_skip_typespec (type); }
return ++type;
case _C_UNION_B:
/* skip name, and elements until closing ')' */
while (*type != _C_UNION_E && *type++ != '=');
while (*type != _C_UNION_E) { type = objc_skip_typespec (type); }
return ++type;
case _C_PTR:
/* Just skip the following typespec */
return objc_skip_typespec (++type);
default:
abort();
}
}
/*
Skip an offset as part of a method encoding. This is prepended by a
'+' if the argument is passed in registers.
*/
inline const char*
objc_skip_offset (const char* type)
{
if (*type == '+') type++;
while(isdigit(*++type));
return type;
}
/*
Skip an argument specification of a method encoding.
*/
const char*
objc_skip_argspec (const char* type)
{
type = objc_skip_typespec (type);
type = objc_skip_offset (type);
return type;
}
unsigned
objc_get_type_qualifiers (const char* type)
{
unsigned res = 0;
BOOL flag = YES;
while (flag)
switch (*type++)
{
case _C_CONST: res |= _F_CONST; break;
case _C_IN: res |= _F_IN; break;
case _C_INOUT: res |= _F_INOUT; break;
case _C_OUT: res |= _F_OUT; break;
case _C_BYCOPY: res |= _F_BYCOPY; break;
case _C_ONEWAY: res |= _F_ONEWAY; break;
default: flag = NO;
}
return res;
}
#endif /* NeXT_runtime */

469
Source/gnu4nextrt.m Normal file
View file

@ -0,0 +1,469 @@
/* Some functionality in the GNU runtime that's not in the NeXT runtime
Copyright (C) 1993,1994 Free Software Foundation, Inc.
Author: Kresten Krab Thorup
Modified by: Andrew McCallum
This file is part of the GNU Objective C Class Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if ! NeXT_runtime
#error This file only needed if using NeXT runtime
#endif /* ! NeXT_runtime */
#include "objects/gnu4next.h"
#include <objc/objc.h>
#include <objc/objc-api.h>
/* Deal with strrchr: */
#if STDC_HEADERS || HAVE_STRING_H
#include <string.h>
/* An ANSI string.h and pre-ANSI memory.h might conflict. */
#if !STDC_HEADERS && HAVE_MEMORY_H
#include <memory.h>
#endif /* not STDC_HEADERS and HAVE_MEMORY_H */
#define index strchr
#define rindex strrchr
#define bcopy(s, d, n) memcpy ((d), (s), (n))
#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n))
#define bzero(s, n) memset ((s), 0, (n))
#else /* not STDC_HEADERS and not HAVE_STRING_H */
#include <strings.h>
/* memory.h and strings.h conflict on some systems. */
#endif /* not STDC_HEADERS and not HAVE_STRING_H */
#define MAX(X, Y) \
({ typeof(X) __x = (X), __y = (Y); \
(__x > __y ? __x : __y); })
#define MIN(X, Y) \
({ typeof(X) __x = (X), __y = (Y); \
(__x < __y ? __x : __y); })
#define ROUND(V, A) \
({ typeof(V) __v=(V); typeof(A) __a=(A); \
__a*((__v+__a-1)/__a); })
static inline int
atoi (const char* str)
{
int res = 0;
while (isdigit (*str))
res *= 10, res += (*str++ - '0');
return res;
}
/*
return the size of an object specified by type
*/
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:
return sizeof(int);
break;
case _C_UINT:
return sizeof(unsigned int);
break;
case _C_LNG:
return sizeof(long);
break;
case _C_ULNG:
return sizeof(unsigned long);
break;
case _C_FLT:
return sizeof(float);
break;
case _C_DBL:
return sizeof(double);
break;
case _C_PTR:
case _C_ATOM:
case _C_CHARPTR:
return sizeof(char*);
break;
case _C_ARY_B:
{
int len = atoi(type+1);
while (isdigit(*++type));
return len*objc_aligned_size (type);
}
break;
case _C_STRUCT_B:
{
int acc_size = 0;
int align;
while (*type != _C_STRUCT_E && *type++ != '='); /* skip "<name>=" */
while (*type != _C_STRUCT_E)
{
align = objc_alignof_type (type); /* padd to alignment */
acc_size = ROUND (acc_size, align);
acc_size += objc_sizeof_type (type); /* add component size */
type = objc_skip_typespec (type); /* skip component */
}
return acc_size;
}
case _C_UNION_B:
{
int max_size = 0;
while (*type != _C_UNION_E && *type++ != '=') /* do nothing */;
while (*type != _C_UNION_E)
{
max_size = MAX (max_size, objc_sizeof_type (type));
type = objc_skip_typespec (type);
}
return max_size;
}
default:
abort();
}
}
/*
Return the alignment of an object specified by type
*/
int
objc_alignof_type(const char* type)
{
switch(*type) {
case _C_ID:
return __alignof__(id);
break;
case _C_CLASS:
return __alignof__(Class);
break;
case _C_SEL:
return __alignof__(SEL);
break;
case _C_CHR:
return __alignof__(char);
break;
case _C_UCHR:
return __alignof__(unsigned char);
break;
case _C_SHT:
return __alignof__(short);
break;
case _C_USHT:
return __alignof__(unsigned short);
break;
case _C_INT:
return __alignof__(int);
break;
case _C_UINT:
return __alignof__(unsigned int);
break;
case _C_LNG:
return __alignof__(long);
break;
case _C_ULNG:
return __alignof__(unsigned long);
break;
case _C_FLT:
return __alignof__(float);
break;
case _C_DBL:
return __alignof__(double);
break;
case _C_ATOM:
case _C_CHARPTR:
return __alignof__(char*);
break;
case _C_ARY_B:
while (isdigit(*++type)) /* do nothing */;
return objc_alignof_type (type);
case _C_STRUCT_B:
{
struct { int x; double y; } fooalign;
while(*type != _C_STRUCT_E && *type++ != '=') /* do nothing */;
if (*type != _C_STRUCT_E)
return MAX (objc_alignof_type (type), __alignof__ (fooalign));
else
return __alignof__ (fooalign);
}
case _C_UNION_B:
{
int maxalign = 0;
while (*type != _C_UNION_E && *type++ != '=') /* do nothing */;
while (*type != _C_UNION_E)
{
maxalign = MAX (maxalign, objc_alignof_type (type));
type = objc_skip_typespec (type);
}
return maxalign;
}
default:
abort();
}
}
/*
The aligned size if the size rounded up to the nearest alignment.
*/
int
objc_aligned_size (const char* type)
{
int size = objc_sizeof_type (type);
int align = objc_alignof_type (type);
return ROUND (size, align);
}
/*
The size rounded up to the nearest integral of the wordsize, taken
to be the size of a void*.
*/
int
objc_promoted_size (const char* type)
{
int size = objc_sizeof_type (type);
int wordsize = sizeof (void*);
return ROUND (size, wordsize);
}
/*
Skip type qualifiers. These may eventually precede typespecs
occuring in method prototype encodings.
*/
inline const char*
objc_skip_type_qualifiers (const char* type)
{
while (*type == _C_CONST
|| *type == _C_IN
|| *type == _C_INOUT
|| *type == _C_OUT
|| *type == _C_BYCOPY
|| *type == _C_ONEWAY)
{
type += 1;
}
return type;
}
/*
Skip one typespec element. If the typespec is prepended by type
qualifiers, these are skipped as well.
*/
const char*
objc_skip_typespec (const char* type)
{
type = objc_skip_type_qualifiers (type);
switch (*type) {
case _C_ID:
/* An id may be annotated by the actual type if it is known
with the @"ClassName" syntax */
if (*++type != '"')
return type;
else
{
while (*++type != '"') /* do nothing */;
return type + 1;
}
/* The following are one character type codes */
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:
case _C_VOID:
return ++type;
break;
case _C_ARY_B:
/* skip digits, typespec and closing ']' */
while(isdigit(*++type));
type = objc_skip_typespec(type);
if (*type == _C_ARY_E)
return ++type;
else
abort();
case _C_STRUCT_B:
/* skip name, and elements until closing '}' */
while (*type != _C_STRUCT_E && *type++ != '=');
while (*type != _C_STRUCT_E) { type = objc_skip_typespec (type); }
return ++type;
case _C_UNION_B:
/* skip name, and elements until closing ')' */
while (*type != _C_UNION_E && *type++ != '=');
while (*type != _C_UNION_E) { type = objc_skip_typespec (type); }
return ++type;
case _C_PTR:
/* Just skip the following typespec */
return objc_skip_typespec (++type);
default:
abort();
}
}
/*
Skip an offset as part of a method encoding. This is prepended by a
'+' if the argument is passed in registers.
*/
inline const char*
objc_skip_offset (const char* type)
{
if (*type == '+') type++;
while(isdigit(*++type));
return type;
}
/*
Skip an argument specification of a method encoding.
*/
const char*
objc_skip_argspec (const char* type)
{
type = objc_skip_typespec (type);
type = objc_skip_offset (type);
return type;
}
unsigned
objc_get_type_qualifiers (const char* type)
{
unsigned res = 0;
BOOL flag = YES;
while (flag)
switch (*type++)
{
case _C_CONST: res |= _F_CONST; break;
case _C_IN: res |= _F_IN; break;
case _C_INOUT: res |= _F_INOUT; break;
case _C_OUT: res |= _F_OUT; break;
case _C_BYCOPY: res |= _F_BYCOPY; break;
case _C_ONEWAY: res |= _F_ONEWAY; break;
default: flag = NO;
}
return res;
}
/* Returns YES iff t1 and t2 have same method types, but we ignore
the argframe layout */
BOOL
sel_types_match (const char* t1, const char* t2)
{
if (!t1 || !t2)
return NO;
while (*t1 && *t2)
{
if (*t1 == '+') t1++;
if (*t2 == '+') t2++;
while (isdigit(*t1)) t1++;
while (isdigit(*t2)) t2++;
/* xxx Remove these next two lines when qualifiers are put in
all selectors, not just Protocol selectors. */
t1 = objc_skip_type_qualifiers(t1);
t2 = objc_skip_type_qualifiers(t2);
if (!*t1 && !*t2)
return YES;
if (*t1 != *t2)
return NO;
t1++;
t2++;
}
return NO;
}

585
Source/o_vprintf.c Normal file
View file

@ -0,0 +1,585 @@
/* Implementation of objects_vprintf for GNU Objective C Class Library
Reworked by: R. Andrew McCallum <mccallum@gnu.ai.mit.edu>
Date: July 1994
This file is part of the GNU Objective C Class Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA. */
/* Reworked from glibc by Andrew McCallum:
Use function pointer argument to put next character.
This is a solution for MemoryStream. It's not ideal.
It is a temporary fix.
On GNU systems we could just use GNU stdio stream functions, but
on non-GNU systems, using this is easier than installing glibc. */
/* #include <ansidecl.h> */
/* #include <localeinfo.h> */
#include <ctype.h>
#include <errno.h>
#include <float.h>
#include <limits.h>
#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* #include <printf.h> */
#include <assert.h>
#include "_itoa.h"
/* If it's an unbuffered stream that we provided
temporary buffering for, remove that buffering. */
#define RETURN(x) \
do \
{ \
done = (x); \
goto do_return; \
} while (0)
#define outchar(x) \
do \
{ \
char outc = (x); \
if ((*write_func)(stream, &outc, 1) == EOF) \
RETURN(-1); \
else \
++done; \
} while (0)
/* Cast the next arg, of type ARGTYPE, into CASTTYPE, and put it in VAR. */
#define castarg(var, argtype, casttype) \
var = (casttype) va_arg(args, argtype)
/* Get the next arg, of type TYPE, and put it in VAR. */
#define nextarg(var, type) castarg(var, type, type)
#ifdef __GNUC__
#define HAVE_LONGLONG
#define LONGLONG long long
#else
#define LONGLONG long
#endif
int
objects_vprintf(void *stream,
int (*write_func)(void*, char*, int len),
const char *format, va_list args)
{
/* Pointer into the format string. */
register const char *f;
/* Number of characters written. */
register size_t done = 0;
/* Reset multibyte characters to their initial state. */
(void) mblen((char *) NULL, 0);
f = format;
while (*f != '\0')
{
/* Type modifiers. */
char is_short, is_long, is_long_double;
#ifdef HAVE_LONGLONG
/* We use the `L' modifier for `long long int'. */
#define is_longlong is_long_double
#else
#define is_longlong 0
#endif
/* Format spec modifiers. */
char space, showsign, left, alt;
/* Padding character: ' ' or '0'. */
char pad;
/* Width of a field. */
register int width;
/* Precision of a field. */
int prec;
/* Decimal integer is negative. */
char is_neg;
/* Current character of the format. */
char fc;
/* Base of a number to be written. */
int base;
/* Integral values to be written. */
unsigned LONGLONG int num;
LONGLONG int signed_num;
/* String to be written. */
const char *str;
char unknown_error[256]; /* Buffer sometimes used by %m. */
if (!isascii(*f))
{
/* Non-ASCII, may be a multibyte. */
int len = mblen(f, strlen(f));
if (len > 0)
{
while (len-- > 0)
outchar(*f++);
continue;
}
}
if (*f != '%')
{
/* This isn't a format spec, so write
everything out until the next one. */
const char *next = strchr(f + 1, '%');
if (next == NULL)
next = strchr(f + 1, '\0');
if (next - f > 20)
{
size_t written = (*write_func)(stream, (void*)f, next - f);
done += written;
if (written != next - f)
break;
f += written;
}
else
while (f < next)
outchar(*f++);
continue;
}
++f;
/* Check for "%%". Note that although the ANSI standard lists
'%' as a conversion specifier, it says "The complete format
specification shall be `%%'," so we can avoid all the width
and precision processing. */
if (*f == '%')
{
++f;
outchar('%');
continue;
}
/* Check for spec modifiers. */
space = showsign = left = alt = 0;
pad = ' ';
while (*f == ' ' || *f == '+' || *f == '-' || *f == '#' || *f == '0')
switch (*f++)
{
case ' ':
/* Output a space in place of a sign, when there is no sign. */
space = 1;
break;
case '+':
/* Always output + or - for numbers. */
showsign = 1;
break;
case '-':
/* Left-justify things. */
left = 1;
break;
case '#':
/* Use the "alternate form":
Hex has 0x or 0X, FP always has a decimal point. */
alt = 1;
break;
case '0':
/* Pad with 0s. */
pad = '0';
break;
}
if (left)
pad = ' ';
/* Get the field width. */
width = 0;
if (*f == '*')
{
/* The field width is given in an argument.
A negative field width indicates left justification. */
nextarg(width, int);
if (width < 0)
{
width = - width;
left = 1;
}
++f;
}
else
while (isdigit(*f))
{
width *= 10;
width += *f++ - '0';
}
/* Get the precision. */
/* -1 means none given; 0 means explicit 0. */
prec = -1;
if (*f == '.')
{
++f;
if (*f == '*')
{
/* The precision is given in an argument. */
nextarg(prec, int);
/* Avoid idiocy. */
if (prec < 0)
prec = -1;
++f;
}
else if (isdigit(*f))
{
prec = 0;
while (*f != '\0' && isdigit(*f))
{
prec *= 10;
prec += *f++ - '0';
}
}
}
/* Check for type modifiers. */
is_short = is_long = is_long_double = 0;
while (*f == 'h' || *f == 'l' || *f == 'L')
switch (*f++)
{
case 'h':
/* int's are short int's. */
is_short = 1;
break;
case 'l':
#ifdef HAVE_LONGLONG
if (is_long)
/* A double `l' is equivalent to an `L'. */
is_longlong = 1;
else
#endif
/* int's are long int's. */
is_long = 1;
break;
case 'L':
/* double's are long double's, and int's are long long int's. */
is_long_double = 1;
break;
case 'Z':
/* int's are size_t's. */
#ifdef HAVE_LONGLONG
assert (sizeof(size_t) <= sizeof(unsigned long long int));
is_longlong = sizeof(size_t) > sizeof(unsigned long int);
#endif
is_long = sizeof(size_t) > sizeof(unsigned int);
break;
}
/* Format specification. */
fc = *f++;
if (1)
switch (fc)
{
case 'i':
case 'd':
/* Decimal integer. */
base = 10;
if (is_longlong)
nextarg(signed_num, LONGLONG int);
else if (is_long)
nextarg(signed_num, long int);
else if (!is_short)
castarg(signed_num, int, long int);
else
castarg(signed_num, int, short int);
is_neg = signed_num < 0;
num = is_neg ? (- signed_num) : signed_num;
goto number;
case 'u':
/* Decimal unsigned integer. */
base = 10;
goto unsigned_number;
case 'o':
/* Octal unsigned integer. */
base = 8;
goto unsigned_number;
case 'X':
/* Hexadecimal unsigned integer. */
case 'x':
/* Hex with lower-case digits. */
base = 16;
unsigned_number:
/* Unsigned number of base BASE. */
if (is_longlong)
castarg(num, LONGLONG int, unsigned LONGLONG int);
else if (is_long)
castarg(num, long int, unsigned long int);
else if (!is_short)
castarg(num, int, unsigned int);
else
castarg(num, int, unsigned short int);
/* ANSI only specifies the `+' and
` ' flags for signed conversions. */
is_neg = showsign = space = 0;
number:
/* Number of base BASE. */
{
char work[BUFSIZ];
char *const workend = &work[sizeof(work) - 1];
register char *w;
/* Supply a default precision if none was given. */
if (prec == -1)
prec = 1;
/* Put the number in WORK. */
w = _itoa (num, workend + 1, base, fc == 'X') - 1;
width -= workend - w;
prec -= workend - w;
if (alt && base == 8 && prec <= 0)
{
*w-- = '0';
--width;
}
if (prec > 0)
{
width -= prec;
while (prec-- > 0)
*w-- = '0';
}
if (alt && base == 16)
width -= 2;
if (is_neg || showsign || space)
--width;
if (!left && pad == ' ')
while (width-- > 0)
outchar(' ');
if (is_neg)
outchar('-');
else if (showsign)
outchar('+');
else if (space)
outchar(' ');
if (alt && base == 16)
{
outchar ('0');
outchar (fc);
}
if (!left && pad == '0')
while (width-- > 0)
outchar('0');
/* Write the number. */
while (++w <= workend)
outchar(*w);
if (left)
while (width-- > 0)
outchar(' ');
}
break;
case 'e':
case 'E':
case 'f':
case 'g':
case 'G':
{
/* Floating-point number. */
extern printf_function __printf_fp;
function = __printf_fp;
goto use_function;
}
case 'c':
/* Character. */
nextarg(num, int);
if (!left)
while (--width > 0)
outchar(' ');
outchar((unsigned char) num);
if (left)
while (--width > 0)
outchar(' ');
break;
case 's':
{
static CONST char null[] = "(null)";
size_t len;
nextarg(str, CONST char *);
string:
if (str == NULL)
/* Write "(null)" if there's space. */
if (prec == -1 || prec >= (int) sizeof(null) - 1)
{
str = null;
len = sizeof(null) - 1;
}
else
{
str = "";
len = 0;
}
else
len = strlen(str);
if (prec != -1 && (size_t) prec < len)
len = prec;
width -= len;
if (!left)
while (width-- > 0)
outchar(' ');
if (len < 20)
while (len-- > 0)
outchar(*str++);
else
if ((*write_func)(stream, str, len) != len)
RETURN(-1);
else
done += len;
if (left)
while (width-- > 0)
outchar(' ');
}
break;
case 'p':
/* Generic pointer. */
{
CONST PTR ptr;
nextarg(ptr, const void*);
if (ptr != NULL)
{
/* If the pointer is not NULL, write it as a %#x spec. */
base = 16;
fc = 'x';
alt = 1;
num = (unsigned LONGLONG int) (unsigned long int) ptr;
is_neg = 0;
goto number;
}
else
{
/* Write "(nil)" for a nil pointer. */
static const char nil[] = "(nil)";
register const char *p;
width -= sizeof (nil) - 1;
if (!left)
while (width-- > 0)
outchar (' ');
for (p = nil; *p != '\0'; ++p)
outchar (*p);
if (left)
while (width-- > 0)
outchar (' ');
}
}
break;
case 'n':
/* Answer the count of characters written. */
if (is_longlong)
{
LONGLONG int *p;
nextarg(p, LONGLONG int *);
*p = done;
}
else if (is_long)
{
long int *p;
nextarg(p, long int *);
*p = done;
}
else if (!is_short)
{
int *p;
nextarg(p, int *);
*p = done;
}
else
{
short int *p;
nextarg(p, short int *);
*p = done;
}
break;
case 'm':
#ifndef HAVE_GNU_LD
#define _sys_errlist sys_errlist
#define _sys_nerr sys_nerr
#endif
if (errno < 0 || errno > _sys_nerr)
{
sprintf (unknown_error, "Unknown error %d", errno);
str = unknown_error;
}
else
str = _sys_errlist[errno];
goto string;
default:
/* Unrecognized format specifier. */
sprintf (unknown_error, "Unknown format specifier %c", fc);
str = unknown_error;
goto string;
}
}
do_return:;
return done;
}

View file

@ -0,0 +1 @@
stdobjects.h

View file

@ -0,0 +1,53 @@
/* Interface for relase pools for delayed disposal
Copyright (C) 1994 Free Software Foundation, Inc.
Written by: R. Andrew McCallum <mccallum@gnu.ai.mit.edu>
Date: May 1993
This file is part of the GNU Objective C Class Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __AutoreleasePool_m_OBJECTS_INCLUDE
#define __AutoreleasePool_m_OBJECTS_INCLUDE
#include <objects/stdobjects.h>
#include <objects/ObjectRetaining.h>
@interface AutoreleasePool : Object
{
AutoreleasePool *parent;
unsigned released_count;
unsigned released_size;
id *released;
}
+ currentPool;
+ (void) autoreleaseObject: anObj;
- (void) autoreleaseObject: anObj;
- init;
@end
@interface Object (Retaining) <Retaining>
@end
void objc_retain_object (id anObj);
void objc_release_object (id anObj);
unsigned objc_retain_count (id anObj);
#endif /* __AutoreleasePool_m_OBJECTS_INCLUDE */

View file

@ -0,0 +1,122 @@
/* Interface to release stack for delayed disposal
Copyright (C) 1994 Free Software Foundation, Inc.
Written by: R. Andrew McCallum <mccallum@gnu.ai.mit.edu>
Date: May 1993
This file is part of the GNU Objective C Class Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __AutoreleaseStack_m_OBJECTS_INCLUDE
#define __AutoreleaseStack_m_OBJECTS_INCLUDE
#include <objects/stdobjects.h>
#include <objects/ObjectRetaining.h>
@interface AutoreleaseStack : Object
{
}
+ (void) autoreleaseObject: anObj;
- (void) autoreleaseObject: anObj;
- init;
@end
void objc_release_stack_objects();
/*
Use of this autorelease class gives -autorelease the following semantics:
- autorelease;
Use this message when the sender is done with this object, but the
sender doesn't want the object to be deallocated immediately
because the function that sends this message will use this object
as its return value. The object will be queued to receive the
actual "release" message only after the caller's caller returns.
(Well, not "queued", "stacked" actually.)
Due to this delayed release, the function that receives the object
as a return value will have the opportunity to retain the object
before the "release" instigated by the "autorelease" actually
takes place.
IMPORTANT PROGRAMMING CONVENTION: Since a autoreleased object may
be freed in the caller's caller's frame, a function must be careful
when returning an object that has been been autoreleased to it
(i.e. returning the object to the autorelease caller's caller's
caller). Since you cannot always know which objects returned to
the current function have been autoreleased by their returners,
you must use the following rule to insure safety for these
situations:
When returning an object that has been allocated, copied or
retained by the returner, return the object as usual. If
returning an object that has been received in this function by
another function, always retain and autorelease the object
before returning it. (Unless, of course, the returner still
needs to keep a reference to the object, in which case the final
autorelease should be omitted.)
The autorelease mechanism works as follows: The implementation of
the "autorelease" method pushes the receiver and the caller's
caller's frame address onto an internally maintained stack. But,
before pushing the reciever, the implementation checks the entries
already on the stack, popping elements off the stack until the
recorded frame address is less than the caller's caller's frame
address. Each object popped off the stack is sent a "release"
message. The stack capacity grows automatically if necessary.
This mechanism ensures that not too many autoreleased objects can
be stacked before we check to see what objects can be released
(i.e. no objects). It also ensures that objects which have been
autoreleased are released as soon as we autorelease any other
object in a lower stack frame.
The only way to build up an unnecessarily large collection of
autoreleased objects is by calling functions that autorelease an
object, and by repeatedly calling those functions from functions
with equal or increasingly higher frame addresses.
Any time that you suspect that you may be creating an unnecessarily
large number of autoreleased objects in a function, (e.g. the
function contains a loop that creates many autoreleased objects
that the function doesn't need), you can always release all the
releasable autoreleased objects for this frame by calling
objc_release_stack_objects(). Be warned that calling this function
will release all objects that have been autoreleased to this
function; if you still need to use some of them, you will have to
retain them beforehand, and release or autorelease them
afterwards.
If desired, you can also use objc_release_stack_objects() at the
top of an event loop, a guaranteed "catch-all" coding practise
similar to the creation and destruction of AutoreleasePool objects
in the event loop.
As an alternative to calling objc_release_stack_objects() you can
also use the same scheme for forcing autorelease's as used for
AutoreleasePool's: s = [[AutoreleaseStack alloc] init], ... code
that autoreleases a bunch of objects to the same stack level ...,
[s release]. It has the same effect.
*/
#endif /* __AutoreleaseStack_m_OBJECTS_INCLUDE */

39
Source/objects/SmallInt.h Normal file
View file

@ -0,0 +1,39 @@
/* Interface for Objective-C efficient small integers
Copyright (C) 1993,1994 Free Software Foundation, Inc.
Written by: R. Andrew McCallum <mccallum@gnu.ai.mit.edu>
Created: Sep 1995
This file is part of the GNU Objective C Class Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __SmallInt_h_INCLUDE_GNU
#define __SmallInt_h_INCLUDE_GNU
#include <objects/stdobjects.h>
#define IS_SMALLINT(OBJ) (((void*)OBJ) & 0x1)
#define ID2INT(OBJ) ((IS_SMALLINT(OBJ)) ? (((int)OBJ) >> 1):[OBJ intValue])
#define INT2ID(I) ((id)((I << 1) & 0x1))
@interface SmallInt : NSObject
-
@end
#endif /* __SmallInt_h_INCLUDE_GNU */

599
Source/vfscanf.c Normal file
View file

@ -0,0 +1,599 @@
/* Implementation of vfscanf for GNU Objective C Class Library
Reworked by: R. Andrew McCallum <mccallum@gnu.ai.mit.edu>
Date: May 1993
This file is part of the GNU Objective C Class Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA. */
/* Reworked from glibc by Andrew McCallum:
Fixed bug by adding "*f == 'a'" to type modifier checking.
Declared extern strtod. */
/* #include <localeinfo.h> */
#include <errno.h>
#include <limits.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern double strtod(const char *str, char **ptr);
#ifdef __GNUC__
#define HAVE_LONGLONG
#define LONGLONG long long
#define CONST const
#define LONG_DOUBLE long double
#else
#define LONGLONG long
#define CONST
#endif
#define inchar() ((c = getc(s)) == EOF ? EOF : (++read_in, c))
#define conv_error() return ((c == EOF || ungetc(c, s)), done)
#define input_error() return (done == 0 ? EOF : done)
#define memory_error() return ((errno = ENOMEM), EOF)
/* Read formatted input from S according to the format string
FORMAT, using the argument list in ARG.
Return the number of assignments made, or -1 for an input error. */
int
objects_vfscanf (FILE *s, const char *format, va_list argptr)
{
va_list arg = (va_list) argptr;
register CONST char *f = format;
register char fc; /* Current character of the format. */
register size_t done = 0; /* Assignments done. */
register size_t read_in = 0; /* Chars read in. */
register int c; /* Last char read. */
register int do_assign; /* Whether to do an assignment. */
register int width; /* Maximum field width. */
/* Type modifiers. */
char is_short, is_long, is_long_double;
#ifdef HAVE_LONGLONG
/* We use the `L' modifier for `long long int'. */
#define is_longlong is_long_double
#else
#define is_longlong 0
#endif
int malloc_string; /* Args are char ** to be filled in. */
/* Status for reading F-P nums. */
char got_dot, got_e;
/* If a [...] is a [^...]. */
char not_in;
/* Base for integral numbers. */
int base;
/* Signedness for integral numbers. */
int number_signed;
/* Integral holding variables. */
long int num;
unsigned long int unum;
/* Floating-point holding variable. */
LONG_DOUBLE fp_num;
/* Character-buffer pointer. */
register char *str, **strptr;
size_t strsize;
/* Workspace. */
char work[200];
char *w; /* Pointer into WORK. */
wchar_t decimal; /* Decimal point character. */
#if 0
if (!__validfp(s) || !s->__mode.__read || format == NULL)
{
errno = EINVAL;
return EOF;
}
#endif
/* Figure out the decimal point character. */
#if 0
if (mbtowc(&decimal, _numeric_info->decimal_point,
strlen(_numeric_info->decimal_point)) <= 0)
decimal = (wchar_t) *_numeric_info->decimal_point;
#else
decimal = '.';
#endif
c = inchar();
/* Run through the format string. */
while (*f != '\0')
{
if (!isascii(*f))
{
/* Non-ASCII, may be a multibyte. */
int len = mblen(f, strlen(f));
if (len > 0)
{
while (len-- > 0)
if (c == EOF)
input_error();
else if (c == *f++)
(void) inchar();
else
conv_error();
continue;
}
}
fc = *f++;
if (fc != '%')
{
/* Characters other than format specs must just match. */
if (c == EOF)
input_error();
if (isspace(fc))
{
/* Whitespace characters match any amount of whitespace. */
while (isspace (c))
inchar ();
continue;
}
else if (c == fc)
(void) inchar();
else
conv_error();
continue;
}
/* Check for the assignment-suppressant. */
if (*f == '*')
{
do_assign = 0;
++f;
}
else
do_assign = 1;
/* Find the maximum field width. */
width = 0;
while (isdigit(*f))
{
width *= 10;
width += *f++ - '0';
}
if (width == 0)
width = -1;
/* Check for type modifiers. */
is_short = is_long = is_long_double = malloc_string = 0;
while (*f == 'h' || *f == 'l' || *f == 'L' || *f == 'a')
switch (*f++)
{
case 'h':
/* int's are short int's. */
is_short = 1;
break;
case 'l':
if (is_long)
/* A double `l' is equivalent to an `L'. */
is_longlong = 1;
else
/* int's are long int's. */
is_long = 1;
break;
case 'L':
/* double's are long double's, and int's are long long int's. */
is_long_double = 1;
break;
case 'a':
/* String conversions (%s, %[) take a `char **'
arg and fill it in with a malloc'd pointer. */
malloc_string = 1;
break;
}
/* End of the format string? */
if (*f == '\0')
conv_error();
/* Find the conversion specifier. */
w = work;
fc = *f++;
if (fc != '[' && fc != 'c' && fc != 'n')
/* Eat whitespace. */
while (isspace(c))
(void) inchar();
switch (fc)
{
case '%': /* Must match a literal '%'. */
if (c != fc)
conv_error();
break;
case 'n': /* Answer number of assignments done. */
if (do_assign)
*va_arg(arg, int *) = read_in;
break;
case 'c': /* Match characters. */
if (do_assign)
{
str = va_arg (arg, char *);
if (str == NULL)
conv_error ();
}
if (c == EOF)
input_error();
if (width == -1)
width = 1;
if (do_assign)
{
do
*str++ = c;
while (inchar() != EOF && --width > 0);
}
else
while (inchar() != EOF && width > 0)
--width;
if (do_assign)
++done;
break;
case 's': /* Read a string. */
#define STRING_ARG \
if (do_assign) \
{ \
if (malloc_string) \
{ \
/* The string is to be stored in a malloc'd buffer. */ \
strptr = va_arg (arg, char **); \
if (strptr == NULL) \
conv_error (); \
/* Allocate an initial buffer. */ \
strsize = 100; \
*strptr = str = malloc (strsize); \
} \
else \
str = va_arg (arg, char *); \
if (str == NULL) \
conv_error (); \
}
STRING_ARG;
if (c == EOF)
input_error ();
do
{
if (isspace (c))
break;
#define STRING_ADD_CHAR(c) \
if (do_assign) \
{ \
*str++ = c; \
if (malloc_string && str == *strptr + strsize) \
{ \
/* Enlarge the buffer. */ \
str = realloc (*strptr, strsize * 2); \
if (str == NULL) \
{ \
/* Can't allocate that much. Last-ditch effort. */\
str = realloc (*strptr, strsize + 1); \
if (str == NULL) \
{ \
/* We lose. Oh well. \
Terminate the string and stop converting, \
so at least we don't swallow any input. */ \
(*strptr)[strsize] = '\0'; \
++done; \
conv_error (); \
} \
else \
{ \
*strptr = str; \
str += strsize; \
++strsize; \
} \
} \
else \
{ \
*strptr = str; \
str += strsize; \
strsize *= 2; \
} \
} \
}
STRING_ADD_CHAR (c);
} while (inchar () != EOF && (width <= 0 || --width > 0));
if (do_assign)
{
*str = '\0';
++done;
}
break;
case 'x': /* Hexadecimal integer. */
case 'X': /* Ditto. */
base = 16;
number_signed = 0;
goto number;
case 'o': /* Octal integer. */
base = 8;
number_signed = 0;
goto number;
case 'u': /* Unsigned decimal integer. */
base = 10;
number_signed = 0;
goto number;
case 'd': /* Signed decimal integer. */
base = 10;
number_signed = 1;
goto number;
case 'i': /* Generic number. */
base = 0;
number_signed = 1;
number:
if (c == EOF)
input_error();
/* Check for a sign. */
if (c == '-' || c == '+')
{
*w++ = c;
if (width > 0)
--width;
(void) inchar();
}
/* Look for a leading indication of base. */
if (c == '0')
{
if (width > 0)
--width;
*w++ = '0';
(void) inchar();
if (tolower(c) == 'x')
{
if (base == 0)
base = 16;
if (base == 16)
{
if (width > 0)
--width;
(void) inchar();
}
}
else if (base == 0)
base = 8;
}
if (base == 0)
base = 10;
/* Read the number into WORK. */
do
{
if (base == 16 ? !isxdigit(c) :
(!isdigit(c) || c - '0' >= base))
break;
*w++ = c;
if (width > 0)
--width;
} while (inchar() != EOF && width != 0);
if (w == work ||
(w - work == 1 && (work[0] == '+' || work[0] == '-')))
/* There was on number. */
conv_error();
/* Convert the number. */
*w = '\0';
if (number_signed)
num = strtol (work, &w, base);
else
#if HAVE_STRTOUL
unum = strtoul (work, &w, base);
#else
unum = strtol (work, &w, base);
#endif
if (w == work)
conv_error ();
if (do_assign)
{
if (! number_signed)
{
if (is_longlong)
*va_arg (arg, unsigned LONGLONG int *) = unum;
else if (is_long)
*va_arg (arg, unsigned long int *) = unum;
else if (is_short)
*va_arg (arg, unsigned short int *)
= (unsigned short int) unum;
else
*va_arg(arg, unsigned int *) = (unsigned int) unum;
}
else
{
if (is_longlong)
*va_arg(arg, LONGLONG int *) = num;
else if (is_long)
*va_arg(arg, long int *) = num;
else if (is_short)
*va_arg(arg, short int *) = (short int) num;
else
*va_arg(arg, int *) = (int) num;
}
++done;
}
break;
case 'e': /* Floating-point numbers. */
case 'E':
case 'f':
case 'g':
case 'G':
if (c == EOF)
input_error();
/* Check for a sign. */
if (c == '-' || c == '+')
{
*w++ = c;
if (inchar() == EOF)
/* EOF is only an input error before we read any chars. */
conv_error();
if (width > 0)
--width;
}
got_dot = got_e = 0;
do
{
if (isdigit(c))
*w++ = c;
else if (got_e && w[-1] == 'e' && (c == '-' || c == '+'))
*w++ = c;
else if (!got_e && tolower(c) == 'e')
{
*w++ = 'e';
got_e = got_dot = 1;
}
else if (c == decimal && !got_dot)
{
*w++ = c;
got_dot = 1;
}
else
break;
if (width > 0)
--width;
} while (inchar() != EOF && width != 0);
if (w == work)
conv_error();
if (w[-1] == '-' || w[-1] == '+' || w[-1] == 'e')
conv_error();
#ifndef MIB_HACKS
/* Convert the number. */
*w = '\0';
fp_num = strtod(work, &w);
if (w == work)
conv_error();
if (do_assign)
{
if (is_long_double)
*va_arg(arg, LONG_DOUBLE *) = fp_num;
else if (is_long)
*va_arg(arg, double *) = (double) fp_num;
else
*va_arg(arg, float *) = (float) fp_num;
++done;
}
break;
#endif /* MIB_HACKS */
case '[': /* Character class. */
STRING_ARG;
if (c == EOF)
input_error();
if (*f == '^')
{
++f;
not_in = 1;
}
else
not_in = 0;
while ((fc = *f++) != '\0' && fc != ']')
{
if (fc == '-' && *f != '\0' && *f != ']' &&
w > work && w[-1] <= *f)
/* Add all characters from the one before the '-'
up to (but not including) the next format char. */
for (fc = w[-1] + 1; fc < *f; ++fc)
*w++ = fc;
else
/* Add the character to the list. */
*w++ = fc;
}
if (fc == '\0')
conv_error();
*w = '\0';
unum = read_in;
do
{
if ((strchr (work, c) == NULL) != not_in)
break;
STRING_ADD_CHAR (c);
if (width > 0)
--width;
} while (inchar () != EOF && width != 0);
if (read_in == unum)
conv_error ();
if (do_assign)
{
*str = '\0';
++done;
}
break;
case 'p': /* Generic pointer. */
base = 16;
/* A PTR must be the same size as a `long int'. */
is_long = 1;
goto number;
}
}
conv_error();
}