mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-10 08:10:49 +00:00
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:
parent
2b5de0130d
commit
5503dfbb4a
29 changed files with 7122 additions and 0 deletions
8
.cvsignore
Normal file
8
.cvsignore
Normal 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
138
BULLETIN
Normal 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}.
|
1
Headers/gnustep/base/.cvsignore
Normal file
1
Headers/gnustep/base/.cvsignore
Normal file
|
@ -0,0 +1 @@
|
|||
stdobjects.h
|
53
Headers/gnustep/base/AutoreleasePool.h
Normal file
53
Headers/gnustep/base/AutoreleasePool.h
Normal 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 */
|
122
Headers/gnustep/base/AutoreleaseStack.h
Normal file
122
Headers/gnustep/base/AutoreleaseStack.h
Normal 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
Headers/gnustep/base/SmallInt.h
Normal file
39
Headers/gnustep/base/SmallInt.h
Normal 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
3
Makefile.local
Normal 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
52
README.ULTRIX
Normal 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
26
README.first
Normal 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
189
Source/MachPort.m
Normal 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
0
Source/Makefile.local
Normal file
135
Source/MethodSignature.m
Normal file
135
Source/MethodSignature.m
Normal 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
42
Source/NSLog.m
Normal 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
43
Source/ProtocolEnforcer.m
Normal 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
76
Source/ReleasePool.m
Normal 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
5
Source/Ring.m
Normal file
|
@ -0,0 +1,5 @@
|
|||
/* Ring.m - a fixed-length circular array */
|
||||
|
||||
@implementation Ring
|
||||
|
||||
@end
|
97
Source/SunRpcPort.m
Normal file
97
Source/SunRpcPort.m
Normal 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
15
Source/Thread.m
Normal 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
476
Source/Tree.m
Normal 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
97
Source/TreeNode.m
Normal 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
441
Source/gnu4next.m
Normal 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
469
Source/gnu4nextrt.m
Normal 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
585
Source/o_vprintf.c
Normal 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;
|
||||
}
|
||||
|
1
Source/objects/.cvsignore
Normal file
1
Source/objects/.cvsignore
Normal file
|
@ -0,0 +1 @@
|
|||
stdobjects.h
|
53
Source/objects/AutoreleasePool.h
Normal file
53
Source/objects/AutoreleasePool.h
Normal 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 */
|
122
Source/objects/AutoreleaseStack.h
Normal file
122
Source/objects/AutoreleaseStack.h
Normal 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
39
Source/objects/SmallInt.h
Normal 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
599
Source/vfscanf.c
Normal 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();
|
||||
}
|
Loading…
Reference in a new issue