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