1995-04-03 22:59:20 +00:00
|
|
|
/* NSDictionary - Dictionary object to store key/value pairs
|
1997-01-06 22:43:08 +00:00
|
|
|
Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
|
1995-04-04 16:15:31 +00:00
|
|
|
|
1996-04-17 20:17:45 +00:00
|
|
|
Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
|
1995-05-05 18:31:51 +00:00
|
|
|
From skeleton by: Adam Fedor <fedor@boulder.colorado.edu>
|
1995-04-03 22:59:20 +00:00
|
|
|
Date: Mar 1995
|
1995-04-04 16:15:31 +00:00
|
|
|
|
1996-05-12 00:56:10 +00:00
|
|
|
This file is part of the GNUstep Base Library.
|
1995-04-04 16:15:31 +00:00
|
|
|
|
1995-04-03 22:59:20 +00:00
|
|
|
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.
|
1995-04-04 16:15:31 +00:00
|
|
|
|
1995-04-03 22:59:20 +00:00
|
|
|
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.
|
1995-04-04 16:15:31 +00:00
|
|
|
*/
|
1995-04-03 22:59:20 +00:00
|
|
|
|
1997-11-06 00:51:23 +00:00
|
|
|
#include <config.h>
|
1997-12-11 19:09:56 +00:00
|
|
|
#include <gnustep/base/behavior.h>
|
1995-04-17 21:13:20 +00:00
|
|
|
#include <Foundation/NSDictionary.h>
|
1995-05-05 18:31:51 +00:00
|
|
|
#include <Foundation/NSGDictionary.h>
|
|
|
|
#include <Foundation/NSArray.h>
|
|
|
|
#include <Foundation/NSUtilities.h>
|
1998-01-19 15:20:15 +00:00
|
|
|
#include <Foundation/NSString.h>
|
|
|
|
#include <Foundation/NSException.h>
|
|
|
|
#include <Foundation/NSAutoreleasePool.h>
|
1995-05-05 18:31:51 +00:00
|
|
|
#include <assert.h>
|
1995-04-03 22:59:20 +00:00
|
|
|
|
1997-10-16 23:56:27 +00:00
|
|
|
@interface NSDictionaryNonCore : NSDictionary
|
|
|
|
@end
|
|
|
|
@interface NSMutableDictionaryNonCore: NSMutableDictionary
|
|
|
|
@end
|
|
|
|
|
1995-04-03 22:59:20 +00:00
|
|
|
@implementation NSDictionary
|
|
|
|
|
1995-06-30 14:21:45 +00:00
|
|
|
static Class NSDictionary_concrete_class;
|
|
|
|
static Class NSMutableDictionary_concrete_class;
|
|
|
|
|
|
|
|
+ (void) _setConcreteClass: (Class)c
|
|
|
|
{
|
|
|
|
NSDictionary_concrete_class = c;
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (void) _setMutableConcreteClass: (Class)c
|
|
|
|
{
|
|
|
|
NSMutableDictionary_concrete_class = c;
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (Class) _concreteClass
|
|
|
|
{
|
|
|
|
return NSDictionary_concrete_class;
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (Class) _mutableConcreteClass
|
|
|
|
{
|
|
|
|
return NSMutableDictionary_concrete_class;
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (void) initialize
|
|
|
|
{
|
1997-10-16 23:56:27 +00:00
|
|
|
if (self == [NSDictionary class])
|
|
|
|
{
|
|
|
|
NSDictionary_concrete_class = [NSGDictionary class];
|
|
|
|
NSMutableDictionary_concrete_class = [NSGMutableDictionary class];
|
|
|
|
behavior_class_add_class (self, [NSDictionaryNonCore class]);
|
|
|
|
}
|
1995-06-30 14:21:45 +00:00
|
|
|
}
|
|
|
|
|
1995-05-05 18:31:51 +00:00
|
|
|
+ allocWithZone: (NSZone*)z
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
1995-06-30 14:21:45 +00:00
|
|
|
return NSAllocateObject([self _concreteClass], 0, z);
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1997-10-16 23:56:27 +00:00
|
|
|
/* This is the designated initializer */
|
|
|
|
- initWithObjects: (id*)objects
|
|
|
|
forKeys: (NSObject**)keys
|
|
|
|
count: (unsigned)count
|
|
|
|
{
|
|
|
|
[self subclassResponsibility:_cmd];
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (unsigned) count
|
|
|
|
{
|
|
|
|
[self subclassResponsibility:_cmd];
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
- objectForKey: (NSObject*)aKey
|
|
|
|
{
|
|
|
|
[self subclassResponsibility:_cmd];
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSEnumerator*) keyEnumerator
|
|
|
|
{
|
|
|
|
[self subclassResponsibility:_cmd];
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSEnumerator*) objectEnumerator
|
|
|
|
{
|
|
|
|
[self subclassResponsibility:_cmd];
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation NSDictionaryNonCore
|
|
|
|
|
1995-05-05 18:31:51 +00:00
|
|
|
+ dictionary
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
1995-11-03 22:18:47 +00:00
|
|
|
return [[[self alloc] init]
|
1995-05-05 18:31:51 +00:00
|
|
|
autorelease];
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1995-05-05 18:31:51 +00:00
|
|
|
+ dictionaryWithObjects: (id*)objects
|
1997-03-03 20:07:35 +00:00
|
|
|
forKeys: (NSObject**)keys
|
1995-05-05 18:31:51 +00:00
|
|
|
count: (unsigned)count
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
1995-11-03 22:18:47 +00:00
|
|
|
return [[[self alloc] initWithObjects:objects
|
|
|
|
forKeys:keys
|
|
|
|
count:count]
|
1995-05-05 18:31:51 +00:00
|
|
|
autorelease];
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1995-05-05 18:31:51 +00:00
|
|
|
- initWithObjects: (NSArray*)objects forKeys: (NSArray*)keys
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
1995-05-05 18:31:51 +00:00
|
|
|
int c = [objects count];
|
|
|
|
id os[c], ks[c];
|
|
|
|
int i;
|
|
|
|
|
|
|
|
assert(c == [keys count]); /* Should be NSException instead */
|
|
|
|
for (i = 0; i < c; i++)
|
|
|
|
{
|
|
|
|
os[i] = [objects objectAtIndex:i];
|
|
|
|
ks[i] = [keys objectAtIndex:i];
|
|
|
|
}
|
|
|
|
return [self initWithObjects:os forKeys:ks count:c];
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1996-10-25 23:43:00 +00:00
|
|
|
+ dictionaryWithObjectsAndKeys: (id)firstObject, ...
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
int capacity = 16;
|
1996-10-31 20:06:15 +00:00
|
|
|
int num_pairs = 0;
|
1996-10-25 23:43:00 +00:00
|
|
|
id *objects;
|
|
|
|
id *keys;
|
|
|
|
id arg;
|
|
|
|
int argi = 1;
|
|
|
|
|
|
|
|
va_start (ap, firstObject);
|
|
|
|
/* Gather all the arguments in a simple array, in preparation for
|
|
|
|
calling the designated initializer. */
|
|
|
|
OBJC_MALLOC (objects, id, capacity);
|
|
|
|
OBJC_MALLOC (keys, id, capacity);
|
|
|
|
if (firstObject != nil)
|
|
|
|
{
|
|
|
|
objects[num_pairs] = firstObject;
|
|
|
|
/* Keep grabbing arguments until we get a nil... */
|
|
|
|
while ((arg = va_arg (ap, id)))
|
|
|
|
{
|
|
|
|
if (num_pairs >= capacity)
|
|
|
|
{
|
|
|
|
/* Must increase capacity in order to fit additional ARG's. */
|
|
|
|
capacity *= 2;
|
|
|
|
OBJC_REALLOC (objects, id, capacity);
|
|
|
|
OBJC_REALLOC (keys, id, capacity);
|
|
|
|
}
|
|
|
|
/* ...and alternately dump them into OBJECTS and KEYS */
|
|
|
|
if (argi++ % 2 == 0)
|
|
|
|
objects[num_pairs] = arg;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
keys[num_pairs] = arg;
|
|
|
|
num_pairs++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
NSAssert (argi % 2 == 0, NSInvalidArgumentException);
|
|
|
|
return [[[self alloc] initWithObjects: objects forKeys: keys
|
|
|
|
count: num_pairs]
|
|
|
|
autorelease];
|
|
|
|
}
|
|
|
|
/* FIRSTOBJECT was nil; just return an empty NSDictionary object. */
|
|
|
|
return [self dictionary];
|
|
|
|
}
|
|
|
|
|
1995-05-05 18:31:51 +00:00
|
|
|
+ dictionaryWithObjects: (NSArray*)objects forKeys: (NSArray*)keys
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
1995-11-03 22:18:47 +00:00
|
|
|
return [[[self alloc] initWithObjects:objects forKeys:keys]
|
1995-05-05 18:31:51 +00:00
|
|
|
autorelease];
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1995-05-05 18:31:51 +00:00
|
|
|
/* Override superclass's designated initializer */
|
|
|
|
- init
|
|
|
|
{
|
|
|
|
return [self initWithObjects:NULL forKeys:NULL count:0];
|
|
|
|
}
|
|
|
|
|
|
|
|
- initWithDictionary: (NSDictionary*)other
|
|
|
|
{
|
|
|
|
int c = [other count];
|
|
|
|
id os[c], ks[c], k, e = [other keyEnumerator];
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
while ((k = [e nextObject]))
|
|
|
|
{
|
|
|
|
ks[i] = k;
|
|
|
|
os[i] = [other objectForKey:k];
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
return [self initWithObjects:os forKeys:ks count:c];
|
|
|
|
}
|
|
|
|
|
|
|
|
- initWithContentsOfFile: (NSString*)path
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
1997-01-06 22:43:08 +00:00
|
|
|
NSString *myString;
|
|
|
|
|
|
|
|
myString = [[NSString alloc] initWithContentsOfFile:path];
|
|
|
|
if (myString)
|
|
|
|
{
|
1997-09-13 17:52:31 +00:00
|
|
|
id result = [myString propertyList];
|
|
|
|
if ( [result isKindOfClass: [NSDictionary class]] )
|
|
|
|
{
|
|
|
|
[self initWithDictionary: result];
|
|
|
|
return self;
|
|
|
|
}
|
1997-01-06 22:43:08 +00:00
|
|
|
}
|
|
|
|
[self autorelease];
|
|
|
|
return nil;
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1997-01-09 16:05:09 +00:00
|
|
|
+ dictionaryWithContentsOfFile:(NSString *)path
|
|
|
|
{
|
|
|
|
return [[[self alloc] initWithContentsOfFile:path]
|
|
|
|
autorelease];
|
|
|
|
}
|
|
|
|
|
1995-05-05 18:31:51 +00:00
|
|
|
- (BOOL) isEqual: other
|
|
|
|
{
|
|
|
|
if ([other isKindOfClass:[NSDictionary class]])
|
|
|
|
return [self isEqualToDictionary:other];
|
|
|
|
return NO;
|
|
|
|
}
|
1995-04-03 22:59:20 +00:00
|
|
|
|
1995-05-05 18:31:51 +00:00
|
|
|
- (BOOL) isEqualToDictionary: (NSDictionary*)other
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
1995-05-05 18:31:51 +00:00
|
|
|
if ([self count] != [other count])
|
|
|
|
return NO;
|
|
|
|
{
|
|
|
|
id k, e = [self keyEnumerator];
|
|
|
|
while ((k = [e nextObject]))
|
1997-10-16 23:56:27 +00:00
|
|
|
{
|
|
|
|
id o1 = [self objectForKey: k];
|
|
|
|
id o2 = [other objectForKey: k];
|
|
|
|
if (![o1 isEqual: o2])
|
|
|
|
return NO;
|
|
|
|
/*
|
1995-05-05 18:31:51 +00:00
|
|
|
if (![[self objectForKey:k] isEqual:[other objectForKey:k]])
|
1997-10-16 23:56:27 +00:00
|
|
|
return NO; */
|
|
|
|
}
|
1995-05-05 18:31:51 +00:00
|
|
|
}
|
|
|
|
/* xxx Recheck this. */
|
|
|
|
return YES;
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1995-05-05 18:31:51 +00:00
|
|
|
- (NSArray*) allKeys
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
1995-05-05 18:31:51 +00:00
|
|
|
id e = [self keyEnumerator];
|
|
|
|
int i, c = [self count];
|
|
|
|
id k[c];
|
|
|
|
|
|
|
|
for (i = 0; i < c; i++)
|
|
|
|
{
|
|
|
|
k[i] = [e nextObject];
|
|
|
|
assert(k[i]);
|
|
|
|
}
|
|
|
|
assert(![e nextObject]);
|
|
|
|
return [[[NSArray alloc] initWithObjects:k count:c]
|
|
|
|
autorelease];
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1995-05-05 18:31:51 +00:00
|
|
|
- (NSArray*) allValues
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
1995-05-05 18:31:51 +00:00
|
|
|
id e = [self objectEnumerator];
|
|
|
|
int i, c = [self count];
|
|
|
|
id k[c];
|
|
|
|
|
|
|
|
for (i = 0; i < c; i++)
|
|
|
|
{
|
|
|
|
k[i] = [e nextObject];
|
|
|
|
assert(k[i]);
|
|
|
|
}
|
|
|
|
assert(![e nextObject]);
|
|
|
|
return [[[NSArray alloc] initWithObjects:k count:c]
|
|
|
|
autorelease];
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1995-05-05 18:31:51 +00:00
|
|
|
- (NSArray*) allKeysForObject: anObject
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
1995-05-05 18:31:51 +00:00
|
|
|
id k, e = [self keyEnumerator];
|
|
|
|
id a[[self count]];
|
|
|
|
int c = 0;
|
|
|
|
|
|
|
|
while ((k = [e nextObject]))
|
1996-04-08 17:19:16 +00:00
|
|
|
if ([anObject isEqual: [self objectForKey: k]])
|
1995-05-05 18:31:51 +00:00
|
|
|
a[c++] = k;
|
1996-04-08 17:19:16 +00:00
|
|
|
return [[[NSArray alloc] initWithObjects: a count: c]
|
1995-05-05 18:31:51 +00:00
|
|
|
autorelease];
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1998-01-19 15:20:15 +00:00
|
|
|
struct foo { NSDictionary *d; SEL s; };
|
|
|
|
|
|
|
|
static int
|
|
|
|
compareIt(id o1, id o2, void* context)
|
|
|
|
{
|
|
|
|
struct foo *f = (struct foo*)context;
|
|
|
|
o1 = [f->d objectForKey: o1];
|
|
|
|
o2 = [f->d objectForKey: o2];
|
|
|
|
return (int)[o1 performSelector: f->s withObject: o2];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray*)keysSortedByValueUsingSelector: (SEL)comp
|
|
|
|
{
|
|
|
|
struct foo info;
|
|
|
|
id k;
|
|
|
|
|
|
|
|
info.d = self;
|
|
|
|
info.s = comp;
|
|
|
|
k = [[self allKeys] sortedArrayUsingFunction: compareIt context: &info];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray*) objectsForKeys: (NSArray*)keys notFoundMarker: (id)marker
|
|
|
|
{
|
|
|
|
int i, c = [keys count];
|
|
|
|
id obuf[c];
|
|
|
|
|
|
|
|
for (i = 0; i < c; i++)
|
|
|
|
{
|
|
|
|
id o = [self objectForKey: [keys objectAtIndex: i]];
|
|
|
|
|
|
|
|
if (o)
|
|
|
|
obuf[i] = o;
|
|
|
|
else
|
|
|
|
obuf[i] = marker;
|
|
|
|
}
|
|
|
|
return [NSArray arrayWithObjects: obuf count: c];
|
|
|
|
}
|
|
|
|
|
1995-04-03 22:59:20 +00:00
|
|
|
- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile
|
|
|
|
{
|
1997-10-31 16:26:44 +00:00
|
|
|
return [[self description] writeToFile:path atomically:useAuxiliaryFile];
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1998-02-12 18:31:59 +00:00
|
|
|
- copy
|
|
|
|
{
|
|
|
|
return [self copyWithZone: [self zone]];
|
|
|
|
}
|
|
|
|
|
1995-05-05 18:31:51 +00:00
|
|
|
- copyWithZone: (NSZone*)z
|
|
|
|
{
|
1995-06-30 14:21:45 +00:00
|
|
|
/* a deep copy */
|
1998-03-12 14:21:20 +00:00
|
|
|
unsigned count = [self count];
|
|
|
|
id oldKeys[count];
|
|
|
|
id newKeys[count];
|
|
|
|
id oldObjects[count];
|
|
|
|
id newObjects[count];
|
|
|
|
id newDictionary;
|
|
|
|
unsigned i;
|
1995-06-30 14:21:45 +00:00
|
|
|
id key;
|
1998-03-12 14:21:20 +00:00
|
|
|
NSEnumerator *enumerator = [self keyEnumerator];
|
|
|
|
BOOL needCopy = [self isKindOfClass: [NSMutableDictionary class]];
|
1995-06-30 14:21:45 +00:00
|
|
|
|
1998-03-12 14:21:20 +00:00
|
|
|
if (NSShouldRetainWithZone(self, z) == NO)
|
|
|
|
needCopy = YES;
|
1995-06-30 14:21:45 +00:00
|
|
|
for (i = 0; (key = [enumerator nextObject]); i++)
|
|
|
|
{
|
1998-03-12 14:21:20 +00:00
|
|
|
oldKeys[i] = key;
|
|
|
|
oldObjects[i] = [self objectForKey:key];
|
|
|
|
newKeys[i] = [oldKeys[i] copyWithZone:z];
|
|
|
|
newObjects[i] = [oldObjects[i] copyWithZone:z];
|
|
|
|
if (oldKeys[i] != newKeys[i] || oldObjects[i] != newObjects[i])
|
|
|
|
needCopy = YES;
|
1995-06-30 14:21:45 +00:00
|
|
|
}
|
1998-03-12 14:21:20 +00:00
|
|
|
if (needCopy)
|
|
|
|
newDictionary = [[[[self class] _concreteClass] alloc]
|
|
|
|
initWithObjects:newObjects
|
|
|
|
forKeys:newKeys
|
1995-06-30 14:21:45 +00:00
|
|
|
count:count];
|
1998-03-12 14:21:20 +00:00
|
|
|
else
|
|
|
|
newDictionary = [self retain];
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
[newKeys[i] release];
|
|
|
|
[newObjects[i] release];
|
|
|
|
}
|
|
|
|
return newDictionary;
|
1995-05-05 18:31:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- mutableCopyWithZone: (NSZone*)z
|
|
|
|
{
|
1995-06-30 14:21:45 +00:00
|
|
|
/* a shallow copy */
|
|
|
|
return [[[[[self class] _mutableConcreteClass] _mutableConcreteClass] alloc]
|
|
|
|
initWithDictionary:self];
|
1995-05-05 18:31:51 +00:00
|
|
|
}
|
1995-04-03 22:59:20 +00:00
|
|
|
|
1998-01-19 15:20:15 +00:00
|
|
|
- (NSString*) description
|
|
|
|
{
|
|
|
|
return [self descriptionWithLocale: nil];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString*) descriptionInStringsFileFormat
|
|
|
|
{
|
|
|
|
NSMutableString *result;
|
|
|
|
int size;
|
|
|
|
int i;
|
1998-02-03 14:20:00 +00:00
|
|
|
NSAutoreleasePool *arp = [[NSAutoreleasePool alloc] init];
|
|
|
|
NSArray *keysArray = [self allKeys];
|
|
|
|
int numKeys = [keysArray count];
|
|
|
|
NSString *plists[numKeys];
|
|
|
|
NSString *keys[numKeys];
|
1998-01-19 15:20:15 +00:00
|
|
|
|
1998-02-03 14:20:00 +00:00
|
|
|
[keysArray getObjects: keys];
|
1998-01-19 15:20:15 +00:00
|
|
|
|
|
|
|
size = 1;
|
|
|
|
|
|
|
|
for (i = 0; i < numKeys; i++) {
|
|
|
|
NSString *newKey;
|
|
|
|
id key;
|
|
|
|
id item;
|
|
|
|
|
1998-02-03 14:20:00 +00:00
|
|
|
key = keys[i];
|
1998-01-19 15:20:15 +00:00
|
|
|
item = [self objectForKey: key];
|
|
|
|
if ([key respondsToSelector: @selector(descriptionForPropertyList)]) {
|
|
|
|
newKey = [key descriptionForPropertyList];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
newKey = [key description];
|
|
|
|
}
|
1998-02-03 14:20:00 +00:00
|
|
|
keys[i] = newKey;
|
1998-01-19 15:20:15 +00:00
|
|
|
|
|
|
|
if (item == nil) {
|
|
|
|
item = @"";
|
|
|
|
}
|
|
|
|
else if ([item isKindOfClass: [NSString class]]) {
|
|
|
|
item = [item descriptionForPropertyList];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
item = [item description];
|
|
|
|
}
|
1998-02-03 14:20:00 +00:00
|
|
|
plists[i] = item;
|
1998-01-19 15:20:15 +00:00
|
|
|
|
1998-02-03 14:20:00 +00:00
|
|
|
size += [newKey length] + [item length];
|
1998-01-19 15:20:15 +00:00
|
|
|
if ([item length]) {
|
|
|
|
size += 5;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
size += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result = [[NSMutableString alloc] initWithCapacity: size];
|
|
|
|
for (i = 0; i < numKeys; i++) {
|
1998-02-03 14:20:00 +00:00
|
|
|
NSString* item = plists[i];
|
1998-01-19 15:20:15 +00:00
|
|
|
|
1998-02-03 14:20:00 +00:00
|
|
|
[result appendString: keys[i]];
|
1998-01-19 15:20:15 +00:00
|
|
|
if ([item length]) {
|
|
|
|
[result appendString: @" = "];
|
|
|
|
[result appendString: item];
|
|
|
|
}
|
|
|
|
[result appendString: @";\n"];
|
|
|
|
}
|
|
|
|
|
|
|
|
[arp release];
|
|
|
|
|
|
|
|
return [result autorelease];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString*) descriptionWithLocale: (NSDictionary*)locale
|
|
|
|
{
|
|
|
|
return [self descriptionWithLocale: locale indent: 0];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSString*) descriptionWithLocale: (NSDictionary*)locale
|
|
|
|
indent: (unsigned int)level
|
|
|
|
{
|
|
|
|
NSMutableString *result;
|
|
|
|
NSEnumerator *enumerator;
|
|
|
|
id key;
|
|
|
|
BOOL canCompare = YES;
|
|
|
|
int count;
|
|
|
|
int size;
|
|
|
|
int indentSize;
|
|
|
|
int indentBase;
|
|
|
|
NSMutableString *iBaseString;
|
|
|
|
NSMutableString *iSizeString;
|
|
|
|
int i;
|
1998-02-03 14:20:00 +00:00
|
|
|
NSAutoreleasePool *arp = [[NSAutoreleasePool alloc] init];
|
|
|
|
NSArray *keyArray = [self allKeys];
|
|
|
|
NSMutableArray *theKeys = [NSMutableArray arrayWithArray: keyArray];
|
|
|
|
int numKeys = [theKeys count];
|
|
|
|
NSString *plists[numKeys];
|
|
|
|
NSString *keys[numKeys];
|
1998-01-19 15:20:15 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Indentation is at four space intervals using tab characters to
|
|
|
|
* replace multiples of eight spaces.
|
|
|
|
*
|
|
|
|
* We work out the sizes of the strings needed to perform indentation for
|
|
|
|
* this level and build strings to make up the indentation.
|
|
|
|
*/
|
|
|
|
indentBase = level << 2;
|
|
|
|
count = indentBase >> 3;
|
|
|
|
if ((indentBase % 8) == 0) {
|
|
|
|
indentBase = count;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
indentBase == count + 4;
|
|
|
|
}
|
|
|
|
iBaseString = [NSMutableString stringWithCapacity: indentBase];
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
[iBaseString appendString: @"\t"];
|
|
|
|
}
|
|
|
|
if (count != indentBase) {
|
|
|
|
[iBaseString appendString: @" "];
|
|
|
|
}
|
|
|
|
|
|
|
|
level++;
|
|
|
|
indentSize = level << 2;
|
|
|
|
count = indentSize >> 3;
|
|
|
|
if ((indentSize % 8) == 0) {
|
|
|
|
indentSize = count;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
indentSize == count + 4;
|
|
|
|
}
|
|
|
|
iSizeString = [NSMutableString stringWithCapacity: indentSize];
|
|
|
|
for (i = 0; i < count; i++) {
|
|
|
|
[iSizeString appendString: @"\t"];
|
|
|
|
}
|
|
|
|
if (count != indentSize) {
|
|
|
|
[iSizeString appendString: @" "];
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Basic size is - opening bracket, newline, closing bracket,
|
|
|
|
* indentation for the closing bracket, and a nul terminator.
|
|
|
|
*/
|
|
|
|
size = 4 + indentBase;
|
|
|
|
|
|
|
|
enumerator = [self keyEnumerator];
|
|
|
|
while ((key = [enumerator nextObject]) != nil) {
|
|
|
|
if ([key respondsToSelector: @selector(compare:)] == NO) {
|
|
|
|
canCompare = NO;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (canCompare) {
|
1998-02-03 14:20:00 +00:00
|
|
|
[theKeys sortUsingSelector: @selector(compare:)];
|
1998-01-19 15:20:15 +00:00
|
|
|
}
|
|
|
|
|
1998-02-03 14:20:00 +00:00
|
|
|
[theKeys getObjects: keys];
|
1998-01-19 15:20:15 +00:00
|
|
|
for (i = 0; i < numKeys; i++) {
|
|
|
|
NSString *newKey;
|
|
|
|
id item;
|
|
|
|
|
1998-02-03 14:20:00 +00:00
|
|
|
key = keys[i];
|
1998-01-19 15:20:15 +00:00
|
|
|
item = [self objectForKey: key];
|
|
|
|
if ([key respondsToSelector: @selector(descriptionForPropertyList)]) {
|
|
|
|
newKey = [key descriptionForPropertyList];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
newKey = [key description];
|
|
|
|
}
|
1998-02-03 14:20:00 +00:00
|
|
|
keys[i] = newKey;
|
1998-01-19 15:20:15 +00:00
|
|
|
|
|
|
|
if ([item isKindOfClass: [NSString class]]) {
|
|
|
|
item = [item descriptionForPropertyList];
|
|
|
|
}
|
|
|
|
else if ([item respondsToSelector:
|
|
|
|
@selector(descriptionWithLocale:indent:)]) {
|
|
|
|
item = [item descriptionWithLocale: locale indent: level];
|
|
|
|
}
|
|
|
|
else if ([item respondsToSelector:
|
|
|
|
@selector(descriptionWithLocale:)]) {
|
|
|
|
item = [item descriptionWithLocale: locale];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
item = [item description];
|
|
|
|
}
|
1998-02-03 14:20:00 +00:00
|
|
|
plists[i] = item;
|
1998-01-19 15:20:15 +00:00
|
|
|
|
1998-02-03 14:20:00 +00:00
|
|
|
size += [newKey length] + [item length] + indentSize;
|
1998-01-19 15:20:15 +00:00
|
|
|
if (i == numKeys - 1) {
|
|
|
|
size += 4; /* ' = ' and newline */
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
size += 5; /* ' = ' and ';' and newline */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
result = [[NSMutableString alloc] initWithCapacity: size];
|
|
|
|
[result appendString: @"{\n"];
|
|
|
|
for (i = 0; i < numKeys; i++) {
|
|
|
|
[result appendString: iSizeString];
|
1998-02-03 14:20:00 +00:00
|
|
|
[result appendString: keys[i]];
|
1998-01-19 15:20:15 +00:00
|
|
|
[result appendString: @" = "];
|
1998-02-03 14:20:00 +00:00
|
|
|
[result appendString: plists[i]];
|
1998-01-19 15:20:15 +00:00
|
|
|
if (i == numKeys - 1) {
|
|
|
|
[result appendString: @"\n"];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
[result appendString: @";\n"];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[result appendString: iBaseString];
|
|
|
|
[result appendString: @"}"];
|
|
|
|
|
|
|
|
[arp release];
|
|
|
|
|
|
|
|
return [result autorelease];
|
|
|
|
}
|
|
|
|
|
1995-04-03 22:59:20 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation NSMutableDictionary
|
|
|
|
|
1997-10-16 23:56:27 +00:00
|
|
|
+ (void)initialize
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
1997-10-16 23:56:27 +00:00
|
|
|
if (self == [NSMutableDictionary class])
|
|
|
|
{
|
|
|
|
behavior_class_add_class (self, [NSMutableDictionaryNonCore class]);
|
|
|
|
behavior_class_add_class (self, [NSDictionaryNonCore class]);
|
|
|
|
}
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1997-10-16 23:56:27 +00:00
|
|
|
+ allocWithZone: (NSZone*)z
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
1997-10-16 23:56:27 +00:00
|
|
|
return NSAllocateObject([self _mutableConcreteClass], 0, z);
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1995-05-05 18:31:51 +00:00
|
|
|
/* This is the designated initializer */
|
|
|
|
- initWithCapacity: (unsigned)numItems
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
1996-02-01 17:04:17 +00:00
|
|
|
[self subclassResponsibility:_cmd];
|
1995-04-04 16:15:31 +00:00
|
|
|
return 0;
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1997-10-16 23:56:27 +00:00
|
|
|
- (void) setObject:anObject forKey:(NSObject *)aKey
|
|
|
|
{
|
|
|
|
[self subclassResponsibility:_cmd];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void) removeObjectForKey:(NSObject *)aKey
|
|
|
|
{
|
|
|
|
[self subclassResponsibility:_cmd];
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation NSMutableDictionaryNonCore
|
|
|
|
|
|
|
|
+ dictionaryWithCapacity: (unsigned)numItems
|
|
|
|
{
|
|
|
|
return [[[self alloc] initWithCapacity:numItems]
|
|
|
|
autorelease];
|
|
|
|
}
|
|
|
|
|
1995-05-05 18:31:51 +00:00
|
|
|
/* Override superclass's designated initializer */
|
|
|
|
- initWithObjects: (id*)objects
|
1997-03-03 20:07:35 +00:00
|
|
|
forKeys: (NSObject**)keys
|
1995-05-05 18:31:51 +00:00
|
|
|
count: (unsigned)count
|
|
|
|
{
|
|
|
|
[self initWithCapacity:count];
|
|
|
|
while (count--)
|
|
|
|
[self setObject:objects[count] forKey:keys[count]];
|
|
|
|
return self;
|
|
|
|
}
|
1995-04-03 22:59:20 +00:00
|
|
|
|
1995-05-05 18:31:51 +00:00
|
|
|
- (void) removeAllObjects
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
1995-05-05 18:31:51 +00:00
|
|
|
id k, e = [self keyEnumerator];
|
|
|
|
while ((k = [e nextObject]))
|
|
|
|
[self removeObjectForKey:k];
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1995-05-05 18:31:51 +00:00
|
|
|
- (void) removeObjectsForKeys: (NSArray*)keyArray
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
1995-05-05 18:31:51 +00:00
|
|
|
int c = [keyArray count];
|
|
|
|
while (c--)
|
|
|
|
[self removeObjectForKey:[keyArray objectAtIndex:c]];
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1995-05-05 18:31:51 +00:00
|
|
|
- (void) addEntriesFromDictionary: (NSDictionary*)other
|
1995-04-03 22:59:20 +00:00
|
|
|
{
|
1995-05-05 18:31:51 +00:00
|
|
|
id k, e = [other keyEnumerator];
|
|
|
|
while ((k = [e nextObject]))
|
|
|
|
[self setObject:[other objectForKey:k] forKey:k];
|
1995-04-03 22:59:20 +00:00
|
|
|
}
|
|
|
|
|
1998-01-19 15:20:15 +00:00
|
|
|
- (void) setDictionary: (NSDictionary*)otherDictionary
|
|
|
|
{
|
|
|
|
[self removeAllObjects];
|
|
|
|
[self addEntriesFromDictionary: otherDictionary];
|
|
|
|
}
|
1995-04-03 22:59:20 +00:00
|
|
|
|
|
|
|
@end
|