diff --git a/Headers/gnustep/base/NSUserDefaults.h b/Headers/gnustep/base/NSUserDefaults.h new file mode 100644 index 000000000..fa26504d7 --- /dev/null +++ b/Headers/gnustep/base/NSUserDefaults.h @@ -0,0 +1,181 @@ +/* Interface for for GNUStep + Copyright (C) 1995, 1996 Free Software Foundation, Inc. + + Written by: Georg Tuparev, EMBL & Academia Naturalis, + Heidelberg, Germany + Tuparev@EMBL-Heidelberg.de + + This file is part of the GNUstep Base 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 __NSUserDefaults_h_OBJECTS_INCLUDE +#define __NSUserDefaults_h_OBJECTS_INCLUDE + +#ifdef NeXT +#import +#import +#else +#include +#include +#endif /* NeXT */ + +@class NSArray; +@class NSMutableArray; +@class NSDictionary; +@class NSMutableDictionary; +@class NSData; + +/* Standard domains */ +extern NSString* NSArgumentDomain; +extern NSString* NSGlobalDomain; +extern NSString* NSRegistrationDomain; + +/* Public notification */ +extern NSString *NSUserDefaultsChanged; + +/* Keys for language-dependent information */ +extern NSString *NSWeekDayNameArray; +extern NSString *NSShortWeekDayNameArray; +extern NSString *NSMonthNameArray; +extern NSString *NSShortMonthNameArray; +extern NSString *NSTimeFormatString; +extern NSString *NSDateFormatString; +extern NSString *NSTimeDateFormatString; +extern NSString *NSShortTimeDateFormatString; +extern NSString *NSCurrencySymbol; +extern NSString *NSDecimalSeparator; +extern NSString *NSThousandsSeparator; +extern NSString *NSInternationalCurrencyString; +extern NSString *NSCurrencyString; +extern NSString *NSDecimalDigits; +extern NSString *NSAMPMDesignation; + +/* NeXTSTEP 4.0 includes some more language-dependent constarnts: +extern NSString *NSHourNameDesignations; +extern NSString *NSYearMonthWeekDesignations; +extern NSString *NSEarlierTimeDesignations; +extern NSString *NSLaterTimeDesignations; +extern NSString *NSThisDayDesignations; +extern NSString *NSNextDayDesignations; +extern NSString *NSNextNextDayDesignations; +extern NSString *NSPriorDayDesignations; +extern NSString *NSDateTimeOrdering; + +Perhaps one day they will be part of OpenStep and we should implement them. +*/ + +/* Get Information about a User */ +#ifndef NEXT_FOUNDATION +extern NSString *NSUserName(void); +extern NSString *NSHomeDirectory(void); +extern NSString *NSHomeDirectoryForUser(NSString * userName); +#endif + + +/* General implementation notes: + + OpenStep spec currently is either complete nor consitent. Therefor + we had to take several implementation decisions which make vary in + different OpenStep implementations. + + - We add a new instance method initWithFile: as a designated + initialization method because it allows to create user defaults + database from a "default user" and also it will work for various + non-posix implementations. + + - We add two new class methods for getting and setting a list of + user languages (userLanguages and setUserLanguages:). They are + somehow equivalent to the NS3.x Application's systemLanguages + method. + + - Definition of argument (command line parameters) + (-GSxxxx || --GSxxx) [value] + + Note: As far as I know, there is nothing like home directory for + the M$ hell. God help the Win95/WinNT users of NSUserDefaults ;-) + + To Do: + - Add writeToFile: instance method; + - implement the description method; + - test for UNIX (write test app); + - ask somebody to test it for M$; + - polish & optimize; + - when tested, fix NSBundle (the system languages stuff); + - write docs :-( + */ + +@interface NSUserDefaults: NSObject +{ +@private + NSMutableArray *searchList; // Current search list; + NSMutableDictionary *persDomains; // Contains persistent defaults info; + NSMutableDictionary *tempDomains; // Contains volatile defaults info; + NSMutableArray *changedDomains; /* ..after first time that persistent + user defaults are changed */ + BOOL tickingTimer; // for synchronization +} + +/* Getting the Shared Instance */ ++ (NSUserDefaults *)standardUserDefaults; ++ (NSArray *)userLanguages; ++ (void)setUserLanguages:(NSArray *)languages; + +/* Initializing the User Defaults */ +- (id)init; +- (id)initWithUser:(NSString *)userName; +- (id)initWithContentsOfFile:(NSString *)path; // This is a new method + +/* Getting and Setting a Default */ +- (NSArray *)arrayForKey:(NSString *)defaultName; +- (BOOL)boolForKey:(NSString *)defaultName; +- (NSData *)dataForKey:(NSString *)defaultName; +- (NSDictionary *)dictionaryForKey:(NSString *)defaultName; +- (float)floatForKey:(NSString *)defaultName; +- (int)integerForKey:(NSString *)defaultName; +- (id)objectForKey:(NSString *)defaultName; +- (void)removeObjectForKey:(NSString *)defaultName; +- (void)setBool:(BOOL)value forKey:(NSString *)defaultName; +- (void)setFloat:(float)value forKey:(NSString *)defaultName; +- (void)setInteger:(int)value forKey:(NSString *)defaultName; +- (void)setObject:(id)value forKey:(NSString *)defaultName; +- (NSArray *)stringArrayForKey:(NSString *)defaultName; +- (NSString *)stringForKey:(NSString *)defaultName; + +/* Returning the Search List */ +- (NSMutableArray *)searchList; + +/* Maintaining Persistent Domains */ +- (NSDictionary *)persistentDomainForName:(NSString *)domainName; +- (NSArray *)persistentDomainNames; +- (void)removePersistentDomainForName:(NSString *)domainName; +- (void)setPersistentDomain:(NSDictionary *)domain + forName:(NSString *)domainName; +- (BOOL)synchronize; + +/* Maintaining Volatile Domains */ +- (void)removeVolatileDomainForName:(NSString *)domainName; +- (void)setVolatileDomain:(NSDictionary *)domain + forName:(NSString *)domainName; +- (NSDictionary *)volatileDomainForName:(NSString *)domainName; +- (NSArray *)volatileDomainNames; + +/* Making Advanced Use of Defaults */ +- (NSDictionary *)dictionaryRepresentation; +- (void)registerDefaults:(NSDictionary *)dictionary; +@end + +#endif /* __NSUserDefaults_h_OBJECTS_INCLUDE */ diff --git a/Headers/gnustep/base/config-win32.h b/Headers/gnustep/base/config-win32.h new file mode 100644 index 000000000..3054b723d --- /dev/null +++ b/Headers/gnustep/base/config-win32.h @@ -0,0 +1,28 @@ + +/* WIN32 extra config stuff */ + +// +// WIN32 +// +#ifdef WIN32 +# include +# ifndef vm_page_size +# define vm_page_size 4096 +# endif +# define popen _popen +#endif + +#define BITSPERBYTE 8 + +/* WIN32 extra config stuff */ + +// +// WIN32 +// +#ifdef WIN32 +# include +# ifndef vm_page_size +# define vm_page_size 4096 +# endif +# define popen _popen +#endif diff --git a/Headers/gnustep/base/config-win32.sed b/Headers/gnustep/base/config-win32.sed new file mode 100644 index 000000000..1852bcca8 --- /dev/null +++ b/Headers/gnustep/base/config-win32.sed @@ -0,0 +1,4 @@ +s/@NeXT_runtime@/0/ +s/@NeXT_cc@/0/ +s/@NeXT_runtime@/0/ +s/@NeXT_cc@/0/ diff --git a/Source/NSUserDefaults.m b/Source/NSUserDefaults.m new file mode 100644 index 000000000..71e850714 --- /dev/null +++ b/Source/NSUserDefaults.m @@ -0,0 +1,745 @@ +/* Implementation for NSUserDefaults for GNUStep + Copyright (C) 1995, 1996 Free Software Foundation, Inc. + + Written by: Georg Tuparev, EMBL & Academia Naturalis, + Heidelberg, Germany + Tuparev@EMBL-Heidelberg.de + + This file is part of the GNUstep Base 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 +#if 0 +/* My Linux doesn't have . Why is this necessary? + What is a work-around that will work for all? -mccallum*/ +#include +/* If POSIX then: #include */ +#endif /* 0 */ +#include +#include +#include +#include + +#ifdef NeXT +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif /* NeXT */ + +/* Wait for access */ +#define _MAX_COUNT 5 /* Max 10 sec. */ + +/* User's Defauls database */ +static NSString* GNU_UserDefaultsDatabese = @"./GNUStep/.GNUstepDefaults"; +static NSString* GNU_UserDefaultsDatabeseLock = @"./GNUStep/.GNUstepUDLock"; + +/************************************************************************* + *** C O N S T A N T S + *************************************************************************/ +/* Standard domains */ +NSString* NSArgumentDomain = @"NSArgumentDomain"; +NSString* NSGlobalDomain = @"NSGlobalDomain"; +NSString* NSRegistrationDomain = @"NSRegistrationDomain"; + +/* Public notification */ +NSString *NSUserDefaultsChanged = @"NSUserDefaultsChanged"; + +/* Keys for language-dependent information */ +NSString *NSWeekDayNameArray = @"NSWeekDayNameArray"; +NSString *NSShortWeekDayNameArray = @"NSShortWeekDayNameArray"; +NSString *NSMonthNameArray = @"NSMonthNameArray"; +NSString *NSShortMonthNameArray = @"NSShortMonthNameArray"; +NSString *NSTimeFormatString = @"NSTimeFormatString"; +NSString *NSDateFormatString = @"NSDateFormatString"; +NSString *NSTimeDateFormatString = @"NSTimeDateFormatString"; +NSString *NSShortTimeDateFormatString = @"NSShortTimeDateFormatString"; +NSString *NSCurrencySymbol = @"NSCurrencySymbol"; +NSString *NSDecimalSeparator = @"NSDecimalSeparator"; +NSString *NSThousandsSeparator = @"NSThousandsSeparator"; +NSString *NSInternationalCurrencyString = @"NSInternationalCurrencyString"; +NSString *NSCurrencyString = @"NSCurrencyString"; +NSString *NSDecimalDigits = @"NSDecimalDigits"; +NSString *NSAMPMDesignation = @"NSAMPMDesignation"; + + +/************************************************************************* + *** Get Information about a User + *************************************************************************/ +#ifndef NeXT +// The functions used below showld work with /etc/passwd file, +// YP and NetInfo. I have no idea how this should be implemented +// for Win-NT and I know that this cannot be implemented fow Win95 + +NSString *NSUserName(void) +{ + NSString* processOwner = [NSString stringWithCString: getlogin()]; + return processOwner; +} + +NSString *NSHomeDirectory(void) +{ + return NSHomeDirectoryForUser (NSUserName()); +} + +NSString *NSHomeDirectoryForUser (NSString * userName) +{ + struct passwd *pwd; + + if (!userName) + return nil; + + setpwent(); // Start scanning the password file + while ((pwd = getpwent ())) + { + if (strcmp(pwd->pw_name,[userName cString]) == 0) + break; + } + endpwent(); // Finish scanning the password file + + if (!pwd) + return nil; + return [NSString stringWithCString:pwd->pw_dir]; +} +#endif + +/************************************************************************* + *** Local method definitions + *************************************************************************/ +@interface NSUserDefaults (__local_NSUserDefaults) +- (void)__createStandardSearchList; +- (NSDictionary *)__createArgumentDictionary; +- (void)__changePersitentDomain:(NSString *)domainName; +@end + +@implementation NSUserDefaults: NSObject +/************************************************************************* + *** Class variables + *************************************************************************/ +static NSUserDefaults *sharedDefaults = nil; +static NSMutableString *defaultsDatabase = nil; +static NSMutableString *defaultsDatabaseLock = nil; +static NSMutableString *processName = nil; + +/************************************************************************* + *** Getting the Shared Instance + *************************************************************************/ ++ (NSUserDefaults *)standardUserDefaults + /* + Returns the shared defaults object. If it doesn't exist yet, it's + created. The defaults are initialized for the current user. + The search list is guaranteed to be standard only the first time + this method is invoked. The shared instance is provided as a + convenience; other instances may also be created. + */ +{ + if (sharedDefaults) + return sharedDefaults; + + // Create new sharedDefaults (NOTE: Not added to the autorelease pool!) + sharedDefaults = [[self alloc] init]; + + [sharedDefaults __createStandardSearchList]; + + return nil; +} + + ++ (NSArray *)userLanguages +{ + NSMutableArray *uL = [NSMutableArray arrayWithCapacity:5]; + NSArray *currLang = [[self standardUserDefaults] + stringArrayForKey:@"Languages"]; + NSEnumerator *enumerator; + id obj; + + if (!currLang) + { // Try to build it from the env + const char *env_list; + NSString *env; + env_list = getenv("LANGUAGES"); + if (env_list) + { + env = [NSString stringWithCString:env_list]; + currLang = [[env componentsSeparatedByString:@";"] retain]; + } + } + [uL addObjectsFromArray:currLang]; + + // Check if "English" is includet + enumerator = [uL objectEnumerator]; + while ((obj = [enumerator nextObject])) + { + if ([obj isEqualToString:@"English"]) + return uL; + } + [uL addObject:@"English"]; + + return uL; +} + ++ (void)setUserLanguages:(NSArray *)languages +{ + NSMutableDictionary *globDict = [[self standardUserDefaults] + persistentDomainForName:NSGlobalDomain]; + + if (!languages) // Remove the entry + [globDict removeObjectForKey:@"Languages"]; + else + [globDict setObject:languages forKey:@"Languages"]; + [[self standardUserDefaults] + setPersistentDomain:globDict forName:NSGlobalDomain]; + return; +} + +/************************************************************************* + *** Initializing the User Defaults + *************************************************************************/ +- (id)init + /* Initializes defaults for current user calling initWithUser:. */ +{ + return [self initWithUser:NSUserName()]; +} + +- (id)initWithUser:(NSString *)userName + /* Initializes defaults for the specified user calling initWithFile:. */ +{ + NSMutableString* userHome = NSHomeDirectoryForUser(userName); + + // Either userName is empty or it's wrong + if (!userHome) + { + [self release]; + return nil; + } + [userHome appendString:GNU_UserDefaultsDatabese]; + + return [self initWithContentsOfFile:userHome]; +} + +- (id)initWithContentsOfFile:(NSString *)path + /* Initializes defaults for the specified path. Returns an object with + an empty search list. */ +{ + [super init]; + + // Find the user's home folder and build the paths (executed only once) + if (!defaultsDatabase) + { + defaultsDatabase = + [[NSMutableString stringWithFormat:@"%@/%@", + NSUserName(), GNU_UserDefaultsDatabese] retain]; + defaultsDatabaseLock = + [[NSMutableString stringWithFormat:@"%@/%@", + NSUserName(), GNU_UserDefaultsDatabeseLock] retain]; + processName = [[[NSProcessInfo processInfo] processName] retain]; +#if 0 + processName = [[NSMutableString stringWithFormat:@"TestApp"] retain]; +#endif + } + + // Create an empty search list + searchList = [[NSMutableArray arrayWithCapacity:10] retain]; + + // Initialize persDomains from the archived user defaults (persistent) + persDomains = [[NSMutableDictionary dictionaryWithCapacity:10] retain]; + [self synchronize]; + + // Check and if not existent add the Application and the Global domains + if (![persDomains objectForKey:processName]) + { + [persDomains setObject: + [NSMutableDictionary + dictionaryWithCapacity:10] forKey:processName]; + [self __changePersitentDomain:processName]; + } + if (![persDomains objectForKey:NSGlobalDomain]) + { + [persDomains setObject: + [NSMutableDictionary + dictionaryWithCapacity:10] forKey:NSGlobalDomain]; + [self __changePersitentDomain:NSGlobalDomain]; + } + + // Create volatile defaults and add the Argument and the Registration domains + tempDomains = [[NSMutableDictionary dictionaryWithCapacity:10] retain]; + [tempDomains setObject:[self __createArgumentDictionary] + forKey:NSArgumentDomain]; + [tempDomains setObject: + [NSMutableDictionary + dictionaryWithCapacity:10] forKey:NSRegistrationDomain]; + + return self; +} + +- (void)dealloc +{ + [searchList release]; + [persDomains release]; + [tempDomains release]; + [changedDomains release]; + [super dealloc]; +} + +- (NSString *)description +{ + NSMutableString *desc = + [NSMutableString stringWithFormat:@"%@",[super description]]; + + // $$$ Not Implemented + // It's good idea to put all useful info here -- so I can test it later + [self notImplemented: _cmd]; + return desc; +} + +/************************************************************************* + *** Getting and Setting a Default + *************************************************************************/ +- (NSArray *)arrayForKey:(NSString *)defaultName +{ + id obj = [self objectForKey:defaultName]; + + if (obj && [obj isKindOfClass:[NSArray class]]) + return obj; + return nil; +} + +- (BOOL)boolForKey:(NSString *)defaultName +{ + id obj = [self stringForKey:defaultName]; + + if (obj + && ([obj isEqualToString:@"YES"] || [obj isEqualToString:@"yes"] + || [obj intValue])) + return YES; + return NO; +} + +- (NSData *)dataForKey:(NSString *)defaultName +{ + id obj = [self objectForKey:defaultName]; + + if (obj && [obj isKindOfClass:[NSData class]]) + return obj; + return nil; +} + +- (NSDictionary *)dictionaryForKey:(NSString *)defaultName +{ + id obj = [self objectForKey:defaultName]; + + if (obj && [obj isKindOfClass:[NSDictionary class]]) + return obj; + return nil; +} + +- (float)floatForKey:(NSString *)defaultName +{ + id obj = [self stringForKey:defaultName]; + + if (obj) + return [obj floatValue]; + return 0.0; +} + +- (int)integerForKey:(NSString *)defaultName +{ + id obj = [self stringForKey:defaultName]; + + if (obj) + return [obj intValue]; + return 0; +} + +- (id)objectForKey:(NSString *)defaultName +{ + NSEnumerator *enumerator = [searchList objectEnumerator]; + id object = nil; + id dN; + + while ((dN = [enumerator nextObject])) + { + id dict; + + dict = [persDomains objectForKey:dN]; + if (dict && (object = [dict objectForKey:defaultName])) + break; + dict = [tempDomains objectForKey:dN]; + if (dict && (object = [dict objectForKey:defaultName])) + break; + } + + return object; +} + +- (void)removeObjectForKey:(NSString *)defaultName +{ + id obj = [[persDomains objectForKey:processName] objectForKey:defaultName]; + + if (obj) + { + [[persDomains objectForKey:processName] removeObjectForKey:defaultName]; + [self __changePersitentDomain:processName]; + } + return; +} + +- (void)setBool:(BOOL)value forKey:(NSString *)defaultName +{ + id obj = (value)?@"YES":@"NO"; + + [self setObject:obj forKey:defaultName]; + return; +} + +- (void)setFloat:(float)value forKey:(NSString *)defaultName +{ + char buf[32]; + sprintf(buf,"%g",value); + [self setObject:[NSString stringWithCString:buf] forKey:defaultName]; + return; +} + +- (void)setInteger:(int)value forKey:(NSString *)defaultName +{ + char buf[32]; + sprintf(buf,"%d",value); + [self setObject:[NSString stringWithCString:buf] forKey:defaultName]; + return; +} + +- (void)setObject:(id)value forKey:(NSString *)defaultName +{ + if (value && defaultName && ([defaultName length] > 0)) + { + [[persDomains objectForKey:processName] + setObject:value forKey:defaultName]; + [self __changePersitentDomain:processName]; + } + return; +} + +- (NSArray *)stringArrayForKey:(NSString *)defaultName +{ + id arr = [self arrayForKey:defaultName]; + + if (arr) + { + NSEnumerator *enumerator = [arr objectEnumerator]; + id obj; + + while ((obj = [enumerator nextObject])) + if ( ! [obj isKindOfClass:[NSString class]]) + return nil; + return arr; + } + return nil; +} + +- (NSString *)stringForKey:(NSString *)defaultName +{ + id obj = [self objectForKey:defaultName]; + + if (obj && [obj isKindOfClass:[NSString class]]) + return obj; + return nil; +} + +/************************************************************************* + *** Returning the Search List + *************************************************************************/ +- (NSMutableArray *)searchList +{ + return searchList; +} + +/************************************************************************* + *** Maintaining Persistent Domains + *************************************************************************/ +- (NSDictionary *)persistentDomainForName:(NSString *)domainName +{ + return [persDomains objectForKey:domainName]; +} + +- (NSArray *)persistentDomainNames +{ + return [persDomains allKeys]; +} + +- (void)removePersistentDomainForName:(NSString *)domainName +{ + if ([persDomains objectForKey:domainName]) + { + [persDomains removeObjectForKey:domainName]; + [self __changePersitentDomain:domainName]; + } + return; +} + +- (void)setPersistentDomain:(NSDictionary *)domain + forName:(NSString *)domainName +{ + id dict = [tempDomains objectForKey:domainName]; + + if (dict) + { + [NSException raise:NSInvalidArgumentException + format:@"Volatile domain with %@ already exists", + domainName]; + return; + } + [persDomains setObject:domain forKey:domainName]; + [self __changePersitentDomain:domainName]; + return; +} + +- (BOOL)synchronize +{ + NSMutableDictionary *newDict = nil; + + tickingTimer = NO; + + // Get file lock + if (mkdir([defaultsDatabase cString],0755) == -1) + return NO; + + // Read the persistent data from the stored database + newDict = [[NSMutableDictionary allocWithZone:[self zone]] + initWithContentsOfFile:defaultsDatabase]; + if (!newDict) + { + rmdir([defaultsDatabaseLock cString]); // release file lock + return NO; + } + + if (changedDomains) + { // Synchronize bpth dictionaries + NSEnumerator *enumerator = [changedDomains objectEnumerator]; + id obj, dict; + + while ((obj = [enumerator nextObject])) + { + dict = [persDomains objectForKey:obj]; + if (dict) // Domane was added or changet + [newDict setObject:dict forKey:obj]; + else // Domain was removed + [newDict removeObjectForKey:obj]; + } + [persDomains release]; + persDomains = newDict; + // Save the changes + if (![persDomains writeToFile:defaultsDatabase atomically:YES]) + { + rmdir([defaultsDatabaseLock cString]); // release file lock + return NO; + } + } + else + { // Just update from disk + [persDomains release]; + persDomains = newDict; + } + + rmdir([defaultsDatabaseLock cString]); // release file lock + + return YES; +} + + +/************************************************************************* + *** Maintaining Volatile Domains + *************************************************************************/ +- (void)removeVolatileDomainForName:(NSString *)domainName +{ + [tempDomains removeObjectForKey:domainName]; + return; +} + +- (void)setVolatileDomain:(NSDictionary *)domain + forName:(NSString *)domainName +{ + id dict = [persDomains objectForKey:domainName]; + + if (dict) + { + [NSException raise:NSInvalidArgumentException + format:@"Persistent domain with %@ already exists", + domainName]; + return; + } + [tempDomains setObject:domain forKey:domainName]; + return; +} + +- (NSDictionary *)volatileDomainForName:(NSString *)domainName +{ + return [tempDomains objectForKey:domainName]; +} + +- (NSArray *)volatileDomainNames +{ + return [tempDomains allKeys]; +} + +/************************************************************************* + *** Making Advanced Use of Defaults + *************************************************************************/ +- (NSDictionary *)dictionaryRepresentation +{ + NSEnumerator *enumerator = [searchList reverseObjectEnumerator]; + NSMutableDictionary *dictRep = + [NSMutableDictionary dictionaryWithCapacity:10]; + id obj; + id dict; + + while ((obj = [enumerator nextObject])) + { + if ( (dict = [persDomains objectForKey:obj]) + || (dict = [tempDomains objectForKey:obj]) ) + [dictRep addEntriesFromDictionary:dict]; + } + // $$$ Should we return NSDictionary here ? + return dictRep; +} + +- (void)registerDefaults:(NSDictionary *)dictionary +{ + [tempDomains setObject:dictionary forKey:NSRegistrationDomain]; + return; +} + +/************************************************************************* + *** Accessing the User Defaults database + *************************************************************************/ +- (void)__createStandardSearchList +{ + NSArray *uL = [[self class] userLanguages]; + NSEnumerator *enumerator = [uL objectEnumerator]; + id object; + + // Note: The search list should exist! + + // 1. NSArgumentDomain + [searchList addObject:NSArgumentDomain]; + + // 2. Application + [searchList addObject:processName]; + + // 3. User's preferred languages + while ((object = [enumerator nextObject])) + { + [searchList addObject:object]; + } + + // 4. NSGlobalDomain + [searchList addObject:NSGlobalDomain]; + + // 5. NSRegistrationDomain + [searchList addObject:NSRegistrationDomain]; + + return; +} + +- (NSDictionary *)__createArgumentDictionary +{ + NSArray *args = [[NSProcessInfo processInfo] arguments]; + //$$$ NSArray *args = searchList; // $$$ + NSEnumerator *enumerator = [args objectEnumerator]; + NSMutableDictionary *argDict = + [NSMutableDictionary dictionaryWithCapacity:2]; + BOOL done; + id key, val; + + done = ((key = [enumerator nextObject]) == nil); + + while (!done) + { + if ([key hasPrefix:@"-GS"] || [key hasPrefix:@"--GS"]) { + val = [enumerator nextObject]; + if (!val) + { // No more args + [argDict setObject:nil forKey:key]; + done = YES; + continue; + } + else if ([val hasPrefix:@"-"]) + { // Yet another argument + [argDict setObject:nil forKey:key]; + key = val; + continue; + } + else + { // Real parameter + [argDict setObject:val forKey:key]; + } + } + done = ((key = [enumerator nextObject]) == nil); + } + + return argDict; +} + +- (void)__changePersitentDomain:(NSString *)domainName +{ + NSEnumerator *enumerator = nil; + id obj; + + if (!changedDomains) + { + changedDomains = [[NSMutableArray arrayWithCapacity:5] retain]; + [[NSNotificationCenter defaultCenter] + postNotificationName:NSUserDefaultsChanged object:nil]; + } + + if (!tickingTimer) + { + [NSTimer scheduledTimerWithTimeInterval:30 + target:self + selector:@selector(synchronize) + userInfo:nil + repeats:NO]; + tickingTimer = YES; + } + + enumerator = [changedDomains objectEnumerator]; + while ((obj = [enumerator nextObject])) + { + if ([obj isEqualToString:domainName]) + return; + } + [changedDomains addObject:domainName]; + return; +} + +@end diff --git a/Testing/release.m b/Testing/release.m new file mode 100644 index 000000000..5b6d4e55b --- /dev/null +++ b/Testing/release.m @@ -0,0 +1,143 @@ +#include +#include +#include +#include "malloc.h" + +@interface ReleaseTester : NSObject +{ + int label; +} +@end + +@implementation ReleaseTester + +- initWithLabel: (int)l +{ + label = l; + return self; +} + +- (oneway void) release +{ + // printf ("release'ing %d\n", label); + [super release]; +} + +- (void) dealloc +{ + // printf ("dealloc'ing %d\n", label); + [super dealloc]; +} + +@end + +void +autorelease_test (int depth) +{ + int n = 2; + id os[n]; + id a = [NSArray new]; + int i; + id arp; + + if (depth < 0) + return; + + arp = [[NSAutoreleasePool alloc] init]; + + for (i = 0; i < n; i++) + { + id r = [[[ReleaseTester alloc] initWithLabel: i+depth*n] autorelease]; + os[i] = r; + [a addObject: r]; + } + +#if 0 + fprintf (stderr, "totalAutoreleasedObjects %d\n", + [NSAutoreleasePool totalAutoreleasedObjects]); +#endif + autorelease_test (depth-1); + + [a release]; + + [arp release]; + + fflush (stdin); +} + +void +release_test (int depth) +{ + int n = 1000; + id os[n]; + int i; + + if (depth < 0) + return; + + for (i = 0; i < n; i++) + os[i] = [[ReleaseTester alloc] initWithLabel: i]; + for (i = 0; i < n; i++) + [os[i] retain]; + for (i = 0; i < n; i++) + [os[i] release]; + for (i = 0; i < n; i++) + [os[i] release]; + + release_test (depth-1); +} + + +#if GNU_LIBC +static void *(*old_malloc_hook) (size_t); +static void (*old_free_hook) (void *ptr); + +static void * +my_malloc_hook (size_t size) +{ + void *result; + __malloc_hook = old_malloc_hook; + result = malloc (size); + /* `printf' might call `malloc', so protect it too. */ + printf ("malloc (%u) returns %p\n", (unsigned int) size, result); + __malloc_hook = my_malloc_hook; + return result; +} + +void +my_free_hook (void *ptr) +{ + __free_hook = old_free_hook; + free (ptr); + __free_hook = my_free_hook; +} +#endif /* GNU_LIBC */ + +int +main () +{ + int i; + +#if GNU_LIBC + old_malloc_hook = __malloc_hook; + old_free_hook = __free_hook; + __malloc_hook = my_malloc_hook; + __free_hook = my_free_hook; +#endif /* GNU_LIBC */ + +#if 1 + for (i = 0; i < 10000; i++) + autorelease_test (3); +#else + /* Checking for memory leak in objc_mutex_lock() */ + _objc_mutex_t gate; + gate = objc_mutex_allocate (); + for (i = 0; i < 1000000; i++) + { + objc_mutex_lock (gate); + objc_mutex_unlock (gate); + } +#endif + + exit (0); +}