mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
New file.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@1651 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
52441fecef
commit
a601e7efea
5 changed files with 1101 additions and 0 deletions
181
Headers/gnustep/base/NSUserDefaults.h
Normal file
181
Headers/gnustep/base/NSUserDefaults.h
Normal file
|
@ -0,0 +1,181 @@
|
|||
/* Interface for <Class> 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 <foundation/NSObject.h>
|
||||
#import <foundation/NSString.h>
|
||||
#else
|
||||
#include <Foundation/NSObject.h>
|
||||
#include <Foundation/NSString.h>
|
||||
#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 */
|
28
Headers/gnustep/base/config-win32.h
Normal file
28
Headers/gnustep/base/config-win32.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
|
||||
/* WIN32 extra config stuff */
|
||||
|
||||
//
|
||||
// WIN32
|
||||
//
|
||||
#ifdef WIN32
|
||||
# include <windows.h>
|
||||
# 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 <windows.h>
|
||||
# ifndef vm_page_size
|
||||
# define vm_page_size 4096
|
||||
# endif
|
||||
# define popen _popen
|
||||
#endif
|
4
Headers/gnustep/base/config-win32.sed
Normal file
4
Headers/gnustep/base/config-win32.sed
Normal file
|
@ -0,0 +1,4 @@
|
|||
s/@NeXT_runtime@/0/
|
||||
s/@NeXT_cc@/0/
|
||||
s/@NeXT_runtime@/0/
|
||||
s/@NeXT_cc@/0/
|
745
Source/NSUserDefaults.m
Normal file
745
Source/NSUserDefaults.m
Normal file
|
@ -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 <gnustep/base/preface.h>
|
||||
#if 0
|
||||
/* My Linux doesn't have <libc.h>. Why is this necessary?
|
||||
What is a work-around that will work for all? -mccallum*/
|
||||
#include <libc.h>
|
||||
/* If POSIX then: #include <unistd.h> */
|
||||
#endif /* 0 */
|
||||
#include <pwd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef NeXT
|
||||
#include <foundation/NSUserDefaults.h>
|
||||
#include <foundation/NSDictionary.h>
|
||||
#include <foundation/NSArray.h>
|
||||
#include <foundation/NSDate.h>
|
||||
#include <foundation/NSUtilities.h>
|
||||
#include <foundation/NSArchiver.h>
|
||||
#include <foundation/NSException.h>
|
||||
#include <foundation/NSNotification.h>
|
||||
#include <foundation/NSTimer.h>
|
||||
#include <foundation/NSProcessInfo.h>
|
||||
#else
|
||||
#include <Foundation/NSUserDefaults.h>
|
||||
#include <Foundation/NSDictionary.h>
|
||||
#include <Foundation/NSArray.h>
|
||||
#include <Foundation/NSDate.h>
|
||||
#include <Foundation/NSUtilities.h>
|
||||
#include <Foundation/NSArchiver.h>
|
||||
#include <Foundation/NSException.h>
|
||||
#include <Foundation/NSNotification.h>
|
||||
#include <Foundation/NSTimer.h>
|
||||
#include <Foundation/NSProcessInfo.h>
|
||||
#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
|
143
Testing/release.m
Normal file
143
Testing/release.m
Normal file
|
@ -0,0 +1,143 @@
|
|||
#include <Foundation/NSObject.h>
|
||||
#include <Foundation/NSArray.h>
|
||||
#include <Foundation/NSAutoreleasePool.h>
|
||||
#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);
|
||||
}
|
Loading…
Reference in a new issue