1997-10-31 16:26:44 +00:00
|
|
|
/* Implementation for NSUserDefaults for GNUstep
|
1996-07-15 18:42:52 +00:00
|
|
|
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
|
1999-09-09 02:56:20 +00:00
|
|
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
1996-07-15 18:42:52 +00:00
|
|
|
*/
|
|
|
|
|
1997-11-06 00:51:23 +00:00
|
|
|
#include <config.h>
|
1998-12-20 21:27:47 +00:00
|
|
|
#include <base/preface.h>
|
1996-07-15 18:42:52 +00:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
#include <Foundation/NSUserDefaults.h>
|
1998-02-09 19:06:40 +00:00
|
|
|
#include <Foundation/NSFileManager.h>
|
1996-09-02 13:20:20 +00:00
|
|
|
#include <Foundation/NSPathUtilities.h>
|
1996-07-15 18:42:52 +00:00
|
|
|
#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>
|
1997-11-03 01:40:03 +00:00
|
|
|
#include <Foundation/NSDistributedLock.h>
|
1998-01-26 14:18:18 +00:00
|
|
|
#include <Foundation/NSRunLoop.h>
|
2000-10-27 15:54:35 +00:00
|
|
|
#include <Foundation/NSBundle.h>
|
|
|
|
#include <base/GSLocale.h>
|
1996-07-15 18:42:52 +00:00
|
|
|
|
|
|
|
/* Wait for access */
|
|
|
|
#define _MAX_COUNT 5 /* Max 10 sec. */
|
|
|
|
|
2000-10-30 18:00:27 +00:00
|
|
|
static SEL nextObjectSel;
|
|
|
|
static SEL objectForKeySel;
|
|
|
|
static SEL addSel;
|
1999-09-28 08:48:27 +00:00
|
|
|
|
|
|
|
/* User's Defaults database */
|
1999-10-05 10:04:12 +00:00
|
|
|
static NSString *GNU_UserDefaultsPrefix = @"GNUstep";
|
|
|
|
static NSString *GNU_UserDefaultsDatabase = @".GNUstepDefaults";
|
|
|
|
static NSString *GNU_UserDefaultsDatabaseLock = @".GNUstepUDLock";
|
1996-07-15 18:42:52 +00:00
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
static Class NSArrayClass;
|
|
|
|
static Class NSDataClass;
|
|
|
|
static Class NSDictionaryClass;
|
|
|
|
static Class NSMutableDictionaryClass;
|
|
|
|
static Class NSStringClass;
|
|
|
|
|
1996-07-15 18:42:52 +00:00
|
|
|
/*************************************************************************
|
|
|
|
*** Local method definitions
|
|
|
|
*************************************************************************/
|
|
|
|
@interface NSUserDefaults (__local_NSUserDefaults)
|
1999-09-28 08:48:27 +00:00
|
|
|
- (void) __createStandardSearchList;
|
|
|
|
- (NSDictionary*) __createArgumentDictionary;
|
|
|
|
- (void) __changePersistentDomain: (NSString*)domainName;
|
|
|
|
- (void) __timerTicked: (NSTimer*)tim;
|
1996-07-15 18:42:52 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation NSUserDefaults: NSObject
|
|
|
|
/*************************************************************************
|
|
|
|
*** Class variables
|
|
|
|
*************************************************************************/
|
|
|
|
static NSUserDefaults *sharedDefaults = nil;
|
|
|
|
static NSMutableString *processName = nil;
|
2000-10-27 15:54:35 +00:00
|
|
|
static NSMutableArray *userLanguages = nil;
|
1996-07-15 18:42:52 +00:00
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
*** Getting the Shared Instance
|
|
|
|
*************************************************************************/
|
1999-02-20 21:19:15 +00:00
|
|
|
static BOOL setSharedDefaults = NO; /* Flag to prevent infinite recursion */
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
+ (void) initialize
|
|
|
|
{
|
|
|
|
if (self == [NSUserDefaults class])
|
|
|
|
{
|
2000-10-30 18:00:27 +00:00
|
|
|
nextObjectSel = @selector(nextObject);
|
|
|
|
objectForKeySel = @selector(objectForKey:);
|
|
|
|
addSel = @selector(addEntriesFromDictionary:);
|
1999-09-28 08:48:27 +00:00
|
|
|
/*
|
|
|
|
* Cache class info for more rapid testing of the types of defaults.
|
|
|
|
*/
|
|
|
|
NSArrayClass = [NSArray class];
|
|
|
|
NSDataClass = [NSData class];
|
|
|
|
NSDictionaryClass = [NSDictionary class];
|
|
|
|
NSMutableDictionaryClass = [NSMutableDictionary class];
|
|
|
|
NSStringClass = [NSString class];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-02-20 21:19:15 +00:00
|
|
|
+ (void) resetUserDefaults
|
|
|
|
{
|
2001-06-15 08:49:03 +00:00
|
|
|
if (sharedDefaults != nil)
|
|
|
|
{
|
|
|
|
NSDictionary *regDefs;
|
|
|
|
|
|
|
|
regDefs = RETAIN([sharedDefaults->_tempDomains
|
|
|
|
objectForKey: NSRegistrationDomain]);
|
|
|
|
setSharedDefaults = NO;
|
|
|
|
DESTROY(sharedDefaults);
|
|
|
|
if (regDefs != nil)
|
|
|
|
{
|
|
|
|
[self standardUserDefaults];
|
|
|
|
if (sharedDefaults != nil)
|
|
|
|
{
|
|
|
|
[sharedDefaults->_tempDomains setObject: regDefs
|
|
|
|
forKey: NSRegistrationDomain];
|
|
|
|
}
|
|
|
|
RELEASE(regDefs);
|
|
|
|
}
|
|
|
|
}
|
1999-02-20 21:19:15 +00:00
|
|
|
}
|
|
|
|
|
2000-10-27 15:54:35 +00:00
|
|
|
/* Create a locale dictionary when we have absolutely no information
|
|
|
|
about the locale. This method should go away, since it will never
|
|
|
|
be called in a properly installed system. */
|
|
|
|
+ (NSDictionary *) _unlocalizedDefaults
|
|
|
|
{
|
|
|
|
NSDictionary *registrationDefaults;
|
|
|
|
NSArray *ampm;
|
|
|
|
NSArray *long_day;
|
|
|
|
NSArray *long_month;
|
|
|
|
NSArray *short_day;
|
|
|
|
NSArray *short_month;
|
|
|
|
NSArray *earlyt;
|
|
|
|
NSArray *latert;
|
|
|
|
NSArray *hour_names;
|
|
|
|
NSArray *ymw_names;
|
|
|
|
|
|
|
|
ampm = [NSArray arrayWithObjects: @"AM", @"PM", nil];
|
2001-07-10 17:19:18 +00:00
|
|
|
|
2000-10-27 15:54:35 +00:00
|
|
|
short_month = [NSArray arrayWithObjects:
|
2001-07-10 17:19:18 +00:00
|
|
|
@"Jan",
|
|
|
|
@"Feb",
|
|
|
|
@"Mar",
|
|
|
|
@"Apr",
|
|
|
|
@"May",
|
|
|
|
@"Jun",
|
|
|
|
@"Jul",
|
|
|
|
@"Aug",
|
|
|
|
@"Sep",
|
|
|
|
@"Oct",
|
|
|
|
@"Nov",
|
|
|
|
@"Dec",
|
|
|
|
nil];
|
|
|
|
|
2000-10-27 15:54:35 +00:00
|
|
|
long_month = [NSArray arrayWithObjects:
|
2001-07-10 17:19:18 +00:00
|
|
|
@"January",
|
|
|
|
@"February",
|
|
|
|
@"March",
|
|
|
|
@"April",
|
|
|
|
@"May",
|
|
|
|
@"June",
|
|
|
|
@"July",
|
|
|
|
@"August",
|
|
|
|
@"September",
|
|
|
|
@"October",
|
|
|
|
@"November",
|
|
|
|
@"December",
|
|
|
|
nil];
|
|
|
|
|
2000-10-27 15:54:35 +00:00
|
|
|
short_day = [NSArray arrayWithObjects:
|
2001-07-10 17:19:18 +00:00
|
|
|
@"Sun",
|
|
|
|
@"Mon",
|
|
|
|
@"Tue",
|
|
|
|
@"Wed",
|
|
|
|
@"Thu",
|
|
|
|
@"Fri",
|
|
|
|
@"Sat",
|
|
|
|
nil];
|
|
|
|
|
2000-10-27 15:54:35 +00:00
|
|
|
long_day = [NSArray arrayWithObjects:
|
2001-07-10 17:19:18 +00:00
|
|
|
@"Sunday",
|
|
|
|
@"Monday",
|
|
|
|
@"Tuesday",
|
|
|
|
@"Wednesday",
|
|
|
|
@"Thursday",
|
|
|
|
@"Friday",
|
|
|
|
@"Saturday",
|
|
|
|
nil];
|
|
|
|
|
2000-10-27 15:54:35 +00:00
|
|
|
earlyt = [NSArray arrayWithObjects:
|
2001-07-10 17:19:18 +00:00
|
|
|
@"prior",
|
|
|
|
@"last",
|
|
|
|
@"past",
|
|
|
|
@"ago",
|
|
|
|
nil];
|
|
|
|
|
|
|
|
latert = [NSArray arrayWithObjects: @"next", nil];
|
|
|
|
|
|
|
|
ymw_names = [NSArray arrayWithObjects: @"year", @"month", @"week", nil];
|
|
|
|
|
2000-10-27 15:54:35 +00:00
|
|
|
hour_names = [NSArray arrayWithObjects:
|
2001-07-10 17:19:18 +00:00
|
|
|
[NSArray arrayWithObjects: @"0", @"midnight", nil],
|
|
|
|
[NSArray arrayWithObjects: @"12", @"noon", @"lunch", nil],
|
|
|
|
[NSArray arrayWithObjects: @"10", @"morning", nil],
|
|
|
|
[NSArray arrayWithObjects: @"14", @"afternoon", nil],
|
|
|
|
[NSArray arrayWithObjects: @"19", @"dinner", nil],
|
|
|
|
nil];
|
|
|
|
|
2000-10-27 15:54:35 +00:00
|
|
|
registrationDefaults = [NSDictionary dictionaryWithObjectsAndKeys:
|
2001-07-10 17:19:18 +00:00
|
|
|
ampm, NSAMPMDesignation,
|
|
|
|
long_month, NSMonthNameArray,
|
|
|
|
long_day, NSWeekDayNameArray,
|
|
|
|
short_month, NSShortMonthNameArray,
|
|
|
|
short_day, NSShortWeekDayNameArray,
|
|
|
|
@"DMYH", NSDateTimeOrdering,
|
|
|
|
[NSArray arrayWithObject: @"tomorrow"], NSNextDayDesignations,
|
|
|
|
[NSArray arrayWithObject: @"nextday"], NSNextNextDayDesignations,
|
|
|
|
[NSArray arrayWithObject: @"yesterday"], NSPriorDayDesignations,
|
|
|
|
[NSArray arrayWithObject: @"today"], NSThisDayDesignations,
|
|
|
|
earlyt, NSEarlierTimeDesignations,
|
|
|
|
latert, NSLaterTimeDesignations,
|
|
|
|
hour_names, NSHourNameDesignations,
|
|
|
|
ymw_names, NSYearMonthWeekDesignations,
|
|
|
|
nil];
|
2000-10-27 15:54:35 +00:00
|
|
|
return registrationDefaults;
|
|
|
|
}
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
+ (NSUserDefaults*) standardUserDefaults
|
1996-07-15 18:42:52 +00:00
|
|
|
/*
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
{
|
2000-10-27 15:54:35 +00:00
|
|
|
BOOL added_locale, added_lang;
|
|
|
|
id lang;
|
|
|
|
NSArray *uL;
|
|
|
|
NSEnumerator *enumerator;
|
|
|
|
|
1999-02-20 21:19:15 +00:00
|
|
|
if (setSharedDefaults)
|
2001-02-22 07:36:05 +00:00
|
|
|
{
|
|
|
|
return sharedDefaults;
|
|
|
|
}
|
1999-02-20 21:19:15 +00:00
|
|
|
setSharedDefaults = YES;
|
2001-02-22 07:36:05 +00:00
|
|
|
/*
|
|
|
|
* Get the user languages *before* setting up sharedDefaults, to avoid
|
|
|
|
* the userLanguages method trying to look up languages in a partially
|
|
|
|
* constructed user defaults object.
|
|
|
|
*/
|
|
|
|
uL = [[self class] userLanguages];
|
1996-07-15 18:42:52 +00:00
|
|
|
// Create new sharedDefaults (NOTE: Not added to the autorelease pool!)
|
|
|
|
sharedDefaults = [[self alloc] init];
|
2000-10-27 15:54:35 +00:00
|
|
|
if (sharedDefaults == nil)
|
|
|
|
{
|
|
|
|
NSLog(@"WARNING - unable to create shared user defaults!\n");
|
|
|
|
return nil;
|
|
|
|
}
|
1996-07-15 18:42:52 +00:00
|
|
|
|
|
|
|
[sharedDefaults __createStandardSearchList];
|
1998-12-06 20:13:32 +00:00
|
|
|
|
2000-10-27 15:54:35 +00:00
|
|
|
/* Set up language constants */
|
|
|
|
added_locale = NO;
|
|
|
|
added_lang = NO;
|
|
|
|
enumerator = [uL objectEnumerator];
|
|
|
|
while ((lang = [enumerator nextObject]))
|
1998-12-06 20:13:32 +00:00
|
|
|
{
|
2000-10-27 15:54:35 +00:00
|
|
|
NSString *path;
|
|
|
|
NSDictionary *dict;
|
|
|
|
path = [NSBundle pathForGNUstepResource: lang
|
|
|
|
ofType: nil
|
|
|
|
inDirectory: @"Resources/Languages"];
|
|
|
|
dict = nil;
|
|
|
|
if (path)
|
|
|
|
dict = [NSDictionary dictionaryWithContentsOfFile: path];
|
|
|
|
if (dict)
|
|
|
|
{
|
|
|
|
[sharedDefaults setVolatileDomain: dict forName: lang];
|
|
|
|
added_lang = YES;
|
|
|
|
}
|
|
|
|
else if (added_locale == NO)
|
|
|
|
{
|
|
|
|
NSString *locale = GSSetLocale(nil);
|
|
|
|
if (locale == nil)
|
|
|
|
break;
|
|
|
|
/* See if we can get the dictionary from i18n functions.
|
|
|
|
Note that we get the dict from the current locale regardless
|
|
|
|
of what 'lang' is, since it should match anyway. */
|
|
|
|
/* Also, I don't think that the i18n routines can handle more than
|
|
|
|
one locale, but tell me if I'm wrong... */
|
|
|
|
if (GSLanguageFromLocale(locale))
|
|
|
|
lang = GSLanguageFromLocale(locale);
|
|
|
|
dict = GSDomainFromDefaultLocale();
|
|
|
|
if (dict)
|
|
|
|
[sharedDefaults setVolatileDomain: dict forName: lang];
|
|
|
|
added_locale = YES;
|
|
|
|
}
|
1998-12-06 20:13:32 +00:00
|
|
|
}
|
2000-10-27 15:54:35 +00:00
|
|
|
if (added_lang == NO)
|
1998-12-13 08:27:53 +00:00
|
|
|
{
|
2000-10-27 15:54:35 +00:00
|
|
|
/* Ack! We should never get here */
|
|
|
|
NSLog(@"Improper installation: No language locale found");
|
|
|
|
[sharedDefaults registerDefaults: [self _unlocalizedDefaults]];
|
1998-12-13 08:27:53 +00:00
|
|
|
}
|
1996-10-31 18:54:23 +00:00
|
|
|
return sharedDefaults;
|
1996-07-15 18:42:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
+ (NSArray*) userLanguages
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
2000-11-16 12:10:37 +00:00
|
|
|
NSArray *currLang = nil;
|
|
|
|
NSString *locale;
|
2000-10-27 15:54:35 +00:00
|
|
|
|
2000-11-16 12:10:37 +00:00
|
|
|
if (userLanguages != nil)
|
|
|
|
{
|
|
|
|
return userLanguages;
|
|
|
|
}
|
2000-10-27 15:54:35 +00:00
|
|
|
userLanguages = RETAIN([NSMutableArray arrayWithCapacity: 5]);
|
|
|
|
locale = GSSetLocale(@"");
|
|
|
|
if (sharedDefaults == nil)
|
|
|
|
{
|
2001-06-15 08:49:03 +00:00
|
|
|
/* Create our own defaults to get "NSLanguages" since sharedDefaults
|
2000-10-27 15:54:35 +00:00
|
|
|
depends on us */
|
2000-11-16 12:10:37 +00:00
|
|
|
NSUserDefaults *tempDefaults;
|
|
|
|
|
2000-10-27 15:54:35 +00:00
|
|
|
tempDefaults = [[self alloc] init];
|
2000-11-16 12:10:37 +00:00
|
|
|
if (tempDefaults != nil)
|
2000-10-27 15:54:35 +00:00
|
|
|
{
|
2001-02-22 07:36:05 +00:00
|
|
|
NSMutableArray *sList;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Can't use the standard method to set up a search list,
|
|
|
|
* it would cause mutual recursion as it includes languages.
|
|
|
|
*/
|
|
|
|
sList = [[NSMutableArray alloc] initWithCapacity: 4];
|
|
|
|
[sList addObject: NSArgumentDomain];
|
|
|
|
[sList addObject: processName];
|
|
|
|
[sList addObject: NSGlobalDomain];
|
|
|
|
[sList addObject: NSRegistrationDomain];
|
|
|
|
[tempDefaults setSearchList: sList];
|
|
|
|
RELEASE(sList);
|
2001-06-15 08:49:03 +00:00
|
|
|
currLang = [tempDefaults stringArrayForKey: @"NSLanguages"];
|
2001-02-22 07:36:05 +00:00
|
|
|
AUTORELEASE(tempDefaults);
|
2000-10-27 15:54:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2000-11-16 12:10:37 +00:00
|
|
|
{
|
2001-06-15 08:49:03 +00:00
|
|
|
currLang
|
|
|
|
= [[self standardUserDefaults] stringArrayForKey: @"NSLanguages"];
|
2000-11-16 12:10:37 +00:00
|
|
|
}
|
|
|
|
if (currLang == nil && locale != 0 && GSLanguageFromLocale(locale))
|
|
|
|
{
|
|
|
|
currLang = [NSArray arrayWithObject: GSLanguageFromLocale(locale)];
|
|
|
|
}
|
2001-06-27 03:13:33 +00:00
|
|
|
#ifdef __MINGW__
|
|
|
|
if (currLang == nil && locale != 0)
|
|
|
|
{
|
|
|
|
/* Check for language as the first part of the locale string */
|
|
|
|
NSRange under = [locale rangeOfString: @"_"];
|
|
|
|
if (under.location)
|
2001-07-16 14:25:47 +00:00
|
|
|
currLang = [NSArray arrayWithObject:
|
|
|
|
[locale substringToIndex: under.location]];
|
2001-06-27 03:13:33 +00:00
|
|
|
}
|
|
|
|
#endif
|
2000-10-27 15:54:35 +00:00
|
|
|
if (currLang == nil)
|
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
const char *env_list;
|
|
|
|
NSString *env;
|
|
|
|
|
1996-07-15 18:42:52 +00:00
|
|
|
env_list = getenv("LANGUAGES");
|
2000-11-16 12:10:37 +00:00
|
|
|
if (env_list != 0)
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
env = [NSStringClass stringWithCString: env_list];
|
2000-11-16 12:10:37 +00:00
|
|
|
currLang = [env componentsSeparatedByString: @";"];
|
1996-07-15 18:42:52 +00:00
|
|
|
}
|
|
|
|
}
|
2000-10-27 15:54:35 +00:00
|
|
|
|
2000-11-01 12:31:21 +00:00
|
|
|
if (currLang != nil)
|
2000-11-16 12:10:37 +00:00
|
|
|
{
|
|
|
|
if ([currLang containsObject: @""] == YES)
|
|
|
|
{
|
|
|
|
NSMutableArray *a = [currLang mutableCopy];
|
|
|
|
|
|
|
|
[a removeObject: @""];
|
|
|
|
currLang = (NSArray*)AUTORELEASE(a);
|
|
|
|
}
|
|
|
|
[userLanguages addObjectsFromArray: currLang];
|
|
|
|
}
|
1996-07-15 18:42:52 +00:00
|
|
|
|
2000-10-27 15:54:35 +00:00
|
|
|
/* Check if "English" is included. We do this to make sure all the
|
|
|
|
required language constants are set somewhere if they aren't set
|
|
|
|
in the default language */
|
|
|
|
if ([userLanguages containsObject: @"English"] == NO)
|
2000-11-16 12:10:37 +00:00
|
|
|
{
|
|
|
|
[userLanguages addObject: @"English"];
|
|
|
|
}
|
|
|
|
|
2000-10-27 15:54:35 +00:00
|
|
|
return userLanguages;
|
1996-07-15 18:42:52 +00:00
|
|
|
}
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
+ (void) setUserLanguages: (NSArray*)languages
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
NSMutableDictionary *globDict = [[self standardUserDefaults]
|
|
|
|
persistentDomainForName: NSGlobalDomain];
|
1996-07-15 18:42:52 +00:00
|
|
|
|
2001-03-05 23:31:51 +00:00
|
|
|
if (languages == nil) // Remove the entry
|
|
|
|
[globDict removeObjectForKey: @"NSLanguages"];
|
1996-07-15 18:42:52 +00:00
|
|
|
else
|
2001-03-05 23:31:51 +00:00
|
|
|
[globDict setObject: languages forKey: @"NSLanguages"];
|
1996-07-15 18:42:52 +00:00
|
|
|
[[self standardUserDefaults]
|
1999-05-06 19:37:45 +00:00
|
|
|
setPersistentDomain: globDict forName: NSGlobalDomain];
|
1996-07-15 18:42:52 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
*** Initializing the User Defaults
|
|
|
|
*************************************************************************/
|
1999-09-28 08:48:27 +00:00
|
|
|
- (id) init
|
1999-05-06 19:37:45 +00:00
|
|
|
/* Initializes defaults for current user calling initWithUser: . */
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-05-06 19:37:45 +00:00
|
|
|
return [self initWithUser: NSUserName()];
|
1996-07-15 18:42:52 +00:00
|
|
|
}
|
|
|
|
|
1999-10-05 10:04:12 +00:00
|
|
|
static NSString *pathForUser(NSString *user)
|
|
|
|
{
|
|
|
|
NSFileManager *mgr = [NSFileManager defaultManager];
|
|
|
|
NSString *home;
|
|
|
|
NSString *path;
|
|
|
|
BOOL isDir;
|
|
|
|
|
|
|
|
home = NSHomeDirectoryForUser(user);
|
|
|
|
if (home == nil)
|
|
|
|
{
|
2000-09-22 04:20:52 +00:00
|
|
|
/* Probably on MINGW. Where to put it? */
|
|
|
|
NSLog(@"Could not get home dir. Using GNUSTEP_ROOT");
|
|
|
|
home = NSOpenStepRootDirectory();
|
|
|
|
path = home;
|
1999-10-05 10:04:12 +00:00
|
|
|
}
|
2000-09-22 04:20:52 +00:00
|
|
|
else
|
|
|
|
path = [home stringByAppendingPathComponent: GNU_UserDefaultsPrefix];
|
1999-10-05 10:04:12 +00:00
|
|
|
if ([mgr fileExistsAtPath: path isDirectory: &isDir] == NO)
|
|
|
|
{
|
2000-03-29 07:00:28 +00:00
|
|
|
NSLog(@"Directory '%@' does not exist - creating it", path);
|
1999-10-05 10:04:12 +00:00
|
|
|
if ([mgr createDirectoryAtPath: path attributes: nil] == NO)
|
|
|
|
{
|
|
|
|
NSLog(@"Unable to create user GNUstep directory '%@'", path);
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (isDir == NO)
|
|
|
|
{
|
|
|
|
NSLog(@"ERROR - '%@' is not a directory!", path);
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
path = [path stringByAppendingPathComponent: GNU_UserDefaultsDatabase];
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
1999-05-06 19:37:45 +00:00
|
|
|
/* Initializes defaults for the specified user calling initWithFile: . */
|
1999-09-28 08:48:27 +00:00
|
|
|
- (id) initWithUser: (NSString*)userName
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-10-05 10:04:12 +00:00
|
|
|
NSString *path = pathForUser(userName);
|
1996-07-15 18:42:52 +00:00
|
|
|
|
1999-10-05 10:04:12 +00:00
|
|
|
if (path == nil)
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-05-20 19:11:21 +00:00
|
|
|
RELEASE(self);
|
1996-07-15 18:42:52 +00:00
|
|
|
return nil;
|
|
|
|
}
|
1999-10-05 10:04:12 +00:00
|
|
|
return [self initWithContentsOfFile: path];
|
1996-07-15 18:42:52 +00:00
|
|
|
}
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
- (id) initWithContentsOfFile: (NSString*)path
|
1996-07-15 18:42:52 +00:00
|
|
|
/* 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)
|
1999-10-05 10:04:12 +00:00
|
|
|
if (_defaultsDatabase == nil)
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1997-11-26 21:15:12 +00:00
|
|
|
if (path != nil && [path isEqual: @""] == NO)
|
1999-10-05 10:04:12 +00:00
|
|
|
{
|
|
|
|
_defaultsDatabase = [path copy];
|
|
|
|
}
|
1997-11-26 21:15:12 +00:00
|
|
|
else
|
1999-05-20 19:11:21 +00:00
|
|
|
{
|
1999-10-05 10:04:12 +00:00
|
|
|
_defaultsDatabase = [pathForUser(NSUserName()) copy];
|
1999-05-20 19:11:21 +00:00
|
|
|
}
|
1997-11-26 21:15:12 +00:00
|
|
|
|
1999-09-16 07:21:34 +00:00
|
|
|
if ([[_defaultsDatabase lastPathComponent] isEqual:
|
1999-10-05 10:04:12 +00:00
|
|
|
GNU_UserDefaultsDatabase] == YES)
|
|
|
|
{
|
|
|
|
path = [_defaultsDatabase stringByDeletingLastPathComponent];
|
|
|
|
}
|
1997-11-26 21:15:12 +00:00
|
|
|
else
|
1999-10-05 10:04:12 +00:00
|
|
|
{
|
|
|
|
path = [pathForUser(NSUserName()) stringByDeletingLastPathComponent];
|
|
|
|
}
|
|
|
|
path = [path stringByAppendingPathComponent:
|
|
|
|
GNU_UserDefaultsDatabaseLock];
|
|
|
|
_defaultsDatabaseLockName = [path copy];
|
1999-09-16 07:21:34 +00:00
|
|
|
_defaultsDatabaseLock =
|
|
|
|
RETAIN([NSDistributedLock lockWithPath: _defaultsDatabaseLockName]);
|
1999-09-28 08:48:27 +00:00
|
|
|
}
|
1997-11-26 21:15:12 +00:00
|
|
|
if (processName == nil)
|
1999-09-03 08:59:07 +00:00
|
|
|
processName = RETAIN([[NSProcessInfo processInfo] processName]);
|
1999-09-09 02:56:20 +00:00
|
|
|
|
1996-07-15 18:42:52 +00:00
|
|
|
// Create an empty search list
|
1999-09-16 07:21:34 +00:00
|
|
|
_searchList = [[NSMutableArray alloc] initWithCapacity: 10];
|
1996-07-15 18:42:52 +00:00
|
|
|
|
1999-09-16 07:21:34 +00:00
|
|
|
// Initialize _persDomains from the archived user defaults (persistent)
|
1999-09-28 08:48:27 +00:00
|
|
|
_persDomains = [[NSMutableDictionaryClass alloc] initWithCapacity: 10];
|
1997-10-31 16:26:44 +00:00
|
|
|
if ([self synchronize] == NO)
|
|
|
|
{
|
1998-01-26 14:18:18 +00:00
|
|
|
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
|
|
|
|
BOOL done = NO;
|
|
|
|
int attempts;
|
|
|
|
|
|
|
|
// Retry for a couple of seconds in case we are locked out.
|
|
|
|
for (attempts = 0; done == NO && attempts < 10; attempts++)
|
|
|
|
{
|
|
|
|
[runLoop runMode: [runLoop currentMode]
|
|
|
|
beforeDate: [NSDate dateWithTimeIntervalSinceNow: 0.2]];
|
|
|
|
if ([self synchronize] == YES)
|
|
|
|
done = YES;
|
|
|
|
}
|
|
|
|
if (done == NO)
|
|
|
|
{
|
1999-05-20 19:11:21 +00:00
|
|
|
RELEASE(self);
|
1998-01-26 14:18:18 +00:00
|
|
|
return self = nil;
|
|
|
|
}
|
1997-10-31 16:26:44 +00:00
|
|
|
}
|
1996-07-15 18:42:52 +00:00
|
|
|
|
|
|
|
// Check and if not existent add the Application and the Global domains
|
1999-09-16 07:21:34 +00:00
|
|
|
if (![_persDomains objectForKey: processName])
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
2000-03-19 09:23:41 +00:00
|
|
|
[_persDomains
|
|
|
|
setObject: [NSMutableDictionaryClass dictionaryWithCapacity: 10]
|
|
|
|
forKey: processName];
|
1999-05-06 19:37:45 +00:00
|
|
|
[self __changePersistentDomain: processName];
|
1996-07-15 18:42:52 +00:00
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
if (![_persDomains objectForKey: NSGlobalDomain])
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
2000-03-19 09:23:41 +00:00
|
|
|
[_persDomains
|
|
|
|
setObject: [NSMutableDictionaryClass dictionaryWithCapacity: 10]
|
|
|
|
forKey: NSGlobalDomain];
|
1999-05-06 19:37:45 +00:00
|
|
|
[self __changePersistentDomain: NSGlobalDomain];
|
1996-07-15 18:42:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create volatile defaults and add the Argument and the Registration domains
|
1999-09-28 08:48:27 +00:00
|
|
|
_tempDomains = [[NSMutableDictionaryClass alloc] initWithCapacity: 10];
|
1999-09-16 07:21:34 +00:00
|
|
|
[_tempDomains setObject: [self __createArgumentDictionary]
|
2000-03-19 09:23:41 +00:00
|
|
|
forKey: NSArgumentDomain];
|
|
|
|
[_tempDomains
|
|
|
|
setObject: [NSMutableDictionaryClass dictionaryWithCapacity: 10]
|
|
|
|
forKey: NSRegistrationDomain];
|
1996-07-15 18:42:52 +00:00
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
- (void) dealloc
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
if (_tickingTimer)
|
|
|
|
[_tickingTimer invalidate];
|
|
|
|
RELEASE(_lastSync);
|
|
|
|
RELEASE(_searchList);
|
|
|
|
RELEASE(_persDomains);
|
|
|
|
RELEASE(_tempDomains);
|
|
|
|
RELEASE(_changedDomains);
|
|
|
|
RELEASE(_dictionaryRep);
|
1996-07-15 18:42:52 +00:00
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
- (NSString*) description
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
2000-03-19 09:23:41 +00:00
|
|
|
NSMutableString *desc;
|
1996-07-15 18:42:52 +00:00
|
|
|
|
2000-03-19 09:23:41 +00:00
|
|
|
desc = [NSMutableString stringWithFormat: @"%@", [super description]];
|
|
|
|
[desc appendFormat: @" SearchList: %@", _searchList];
|
|
|
|
[desc appendFormat: @" Persistant: %@", _persDomains];
|
|
|
|
[desc appendFormat: @" Temporary: %@", _tempDomains];
|
1996-07-15 18:42:52 +00:00
|
|
|
return desc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
*** Getting and Setting a Default
|
|
|
|
*************************************************************************/
|
1999-09-28 08:48:27 +00:00
|
|
|
- (NSArray*) arrayForKey: (NSString*)defaultName
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
id obj = [self objectForKey: defaultName];
|
1996-07-15 18:42:52 +00:00
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
if (obj != nil && [obj isKindOfClass: NSArrayClass])
|
1996-07-15 18:42:52 +00:00
|
|
|
return obj;
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
- (BOOL) boolForKey: (NSString*)defaultName
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
id obj = [self stringForKey: defaultName];
|
1996-07-15 18:42:52 +00:00
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
if (obj != nil)
|
1999-07-28 08:53:35 +00:00
|
|
|
return [obj boolValue];
|
1996-07-15 18:42:52 +00:00
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
- (NSData*) dataForKey: (NSString*)defaultName
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
id obj = [self objectForKey: defaultName];
|
1996-07-15 18:42:52 +00:00
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
if (obj != nil && [obj isKindOfClass: NSDataClass])
|
1996-07-15 18:42:52 +00:00
|
|
|
return obj;
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
- (NSDictionary*) dictionaryForKey: (NSString*)defaultName
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
id obj = [self objectForKey: defaultName];
|
1996-07-15 18:42:52 +00:00
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
if (obj != nil && [obj isKindOfClass: NSDictionaryClass])
|
1996-07-15 18:42:52 +00:00
|
|
|
return obj;
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
- (float) floatForKey: (NSString*)defaultName
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
id obj = [self stringForKey: defaultName];
|
1996-07-15 18:42:52 +00:00
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
if (obj != nil)
|
1996-07-15 18:42:52 +00:00
|
|
|
return [obj floatValue];
|
|
|
|
return 0.0;
|
|
|
|
}
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
- (int) integerForKey: (NSString*)defaultName
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
id obj = [self stringForKey: defaultName];
|
1996-07-15 18:42:52 +00:00
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
if (obj != nil)
|
1996-07-15 18:42:52 +00:00
|
|
|
return [obj intValue];
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
- (id) objectForKey: (NSString*)defaultName
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
NSEnumerator *enumerator = [_searchList objectEnumerator];
|
|
|
|
IMP nImp = [enumerator methodForSelector: nextObjectSel];
|
|
|
|
id object = nil;
|
|
|
|
id dN;
|
|
|
|
IMP pImp = [_persDomains methodForSelector: objectForKeySel];
|
|
|
|
IMP tImp = [_tempDomains methodForSelector: objectForKeySel];
|
1996-07-15 18:42:52 +00:00
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
while ((dN = (*nImp)(enumerator, nextObjectSel)) != nil)
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
id dict;
|
1996-07-15 18:42:52 +00:00
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
dict = (*pImp)(_persDomains, objectForKeySel, dN);
|
|
|
|
if (dict != nil && (object = [dict objectForKey: defaultName]))
|
1996-07-15 18:42:52 +00:00
|
|
|
break;
|
1999-09-28 08:48:27 +00:00
|
|
|
dict = (*tImp)(_tempDomains, objectForKeySel, dN);
|
|
|
|
if (dict != nil && (object = [dict objectForKey: defaultName]))
|
1996-07-15 18:42:52 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
- (void) removeObjectForKey: (NSString*)defaultName
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
id obj;
|
1996-07-15 18:42:52 +00:00
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
obj = [[_persDomains objectForKey: processName] objectForKey: defaultName];
|
|
|
|
if (obj != nil)
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
NSMutableDictionary *dict;
|
|
|
|
id obj = [_persDomains objectForKey: processName];
|
1998-09-04 06:49:38 +00:00
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
if ([obj isKindOfClass: NSMutableDictionaryClass] == YES)
|
1998-09-04 06:49:38 +00:00
|
|
|
{
|
|
|
|
dict = obj;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dict = [obj mutableCopy];
|
1999-09-16 07:21:34 +00:00
|
|
|
[_persDomains setObject: dict forKey: processName];
|
1998-09-04 06:49:38 +00:00
|
|
|
}
|
1999-05-06 19:37:45 +00:00
|
|
|
[dict removeObjectForKey: defaultName];
|
|
|
|
[self __changePersistentDomain: processName];
|
1996-07-15 18:42:52 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
- (void) setBool: (BOOL)value forKey: (NSString*)defaultName
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
id obj = (value)?@"YES": @"NO";
|
1996-07-15 18:42:52 +00:00
|
|
|
|
1999-05-06 19:37:45 +00:00
|
|
|
[self setObject: obj forKey: defaultName];
|
1996-07-15 18:42:52 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
- (void) setFloat: (float)value forKey: (NSString*)defaultName
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
char buf[32];
|
|
|
|
|
1996-07-15 18:42:52 +00:00
|
|
|
sprintf(buf,"%g",value);
|
1999-09-28 08:48:27 +00:00
|
|
|
[self setObject: [NSStringClass stringWithCString: buf] forKey: defaultName];
|
1996-07-15 18:42:52 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
- (void) setInteger: (int)value forKey: (NSString*)defaultName
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
char buf[32];
|
|
|
|
|
1996-07-15 18:42:52 +00:00
|
|
|
sprintf(buf,"%d",value);
|
1999-09-28 08:48:27 +00:00
|
|
|
[self setObject: [NSStringClass stringWithCString: buf] forKey: defaultName];
|
1996-07-15 18:42:52 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
- (void) setObject: (id)value forKey: (NSString*)defaultName
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
|
|
|
if (value && defaultName && ([defaultName length] > 0))
|
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
NSMutableDictionary *dict;
|
|
|
|
id obj = [_persDomains objectForKey: processName];
|
1998-09-04 06:33:30 +00:00
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
if ([obj isKindOfClass: NSMutableDictionaryClass] == YES)
|
1998-09-04 06:33:30 +00:00
|
|
|
{
|
|
|
|
dict = obj;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dict = [obj mutableCopy];
|
1999-09-16 07:21:34 +00:00
|
|
|
[_persDomains setObject: dict forKey: processName];
|
1999-09-28 08:48:27 +00:00
|
|
|
RELEASE(dict);
|
1998-09-04 06:33:30 +00:00
|
|
|
}
|
1999-05-06 19:37:45 +00:00
|
|
|
[dict setObject: value forKey: defaultName];
|
|
|
|
[self __changePersistentDomain: processName];
|
1996-07-15 18:42:52 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
- (NSArray*) stringArrayForKey: (NSString*)defaultName
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
id arr = [self arrayForKey: defaultName];
|
1996-07-15 18:42:52 +00:00
|
|
|
|
2000-11-16 12:10:37 +00:00
|
|
|
if (arr != nil)
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
NSEnumerator *enumerator = [arr objectEnumerator];
|
|
|
|
id obj;
|
1996-07-15 18:42:52 +00:00
|
|
|
|
|
|
|
while ((obj = [enumerator nextObject]))
|
2000-11-16 12:10:37 +00:00
|
|
|
{
|
|
|
|
if ([obj isKindOfClass: NSStringClass] == NO)
|
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
}
|
1996-07-15 18:42:52 +00:00
|
|
|
return arr;
|
|
|
|
}
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
- (NSString*) stringForKey: (NSString*)defaultName
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
id obj = [self objectForKey: defaultName];
|
1996-07-15 18:42:52 +00:00
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
if (obj != nil && [obj isKindOfClass: NSStringClass])
|
1996-07-15 18:42:52 +00:00
|
|
|
return obj;
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
*** Returning the Search List
|
|
|
|
*************************************************************************/
|
1999-09-28 08:48:27 +00:00
|
|
|
- (NSArray*) searchList
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
return AUTORELEASE([_searchList copy]);
|
1996-07-15 18:42:52 +00:00
|
|
|
}
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
- (void) setSearchList: (NSArray*)newList
|
1997-10-31 16:26:44 +00:00
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
DESTROY(_dictionaryRep);
|
|
|
|
RELEASE(_searchList);
|
|
|
|
_searchList = [newList mutableCopy];
|
1997-10-31 16:26:44 +00:00
|
|
|
}
|
|
|
|
|
1996-07-15 18:42:52 +00:00
|
|
|
/*************************************************************************
|
|
|
|
*** Maintaining Persistent Domains
|
|
|
|
*************************************************************************/
|
1999-09-28 08:48:27 +00:00
|
|
|
- (NSDictionary*) persistentDomainForName: (NSString*)domainName
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
return AUTORELEASE([[_persDomains objectForKey: domainName] copy]);
|
1996-07-15 18:42:52 +00:00
|
|
|
}
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
- (NSArray*) persistentDomainNames
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
return [_persDomains allKeys];
|
1996-07-15 18:42:52 +00:00
|
|
|
}
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
- (void) removePersistentDomainForName: (NSString*)domainName
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
if ([_persDomains objectForKey: domainName])
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
[_persDomains removeObjectForKey: domainName];
|
1999-05-06 19:37:45 +00:00
|
|
|
[self __changePersistentDomain: domainName];
|
1996-07-15 18:42:52 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
- (void) setPersistentDomain: (NSDictionary*)domain
|
|
|
|
forName: (NSString*)domainName
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
id dict = [_tempDomains objectForKey: domainName];
|
1996-07-15 18:42:52 +00:00
|
|
|
|
|
|
|
if (dict)
|
|
|
|
{
|
1999-05-06 19:37:45 +00:00
|
|
|
[NSException raise: NSInvalidArgumentException
|
1999-09-28 08:48:27 +00:00
|
|
|
format: @"Persistant domain %@ already exists", domainName];
|
1996-07-15 18:42:52 +00:00
|
|
|
return;
|
|
|
|
}
|
1999-09-28 08:48:27 +00:00
|
|
|
domain = [domain mutableCopy];
|
1999-09-16 07:21:34 +00:00
|
|
|
[_persDomains setObject: domain forKey: domainName];
|
1999-09-28 08:48:27 +00:00
|
|
|
RELEASE(domain);
|
1999-05-06 19:37:45 +00:00
|
|
|
[self __changePersistentDomain: domainName];
|
1996-07-15 18:42:52 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1999-02-05 11:44:38 +00:00
|
|
|
- (BOOL) synchronize
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-05-20 19:11:21 +00:00
|
|
|
NSFileManager *mgr = [NSFileManager defaultManager];
|
1999-09-28 08:48:27 +00:00
|
|
|
NSMutableDictionary *newDict;
|
1999-05-20 19:11:21 +00:00
|
|
|
NSDictionary *attr;
|
|
|
|
NSDate *mod;
|
|
|
|
|
1999-09-16 07:21:34 +00:00
|
|
|
if (_tickingTimer == nil)
|
1999-01-19 12:58:53 +00:00
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
_tickingTimer = [NSTimer scheduledTimerWithTimeInterval: 30
|
1999-02-05 11:44:38 +00:00
|
|
|
target: self
|
1999-05-20 19:11:21 +00:00
|
|
|
selector: @selector(__timerTicked:)
|
1999-02-05 11:44:38 +00:00
|
|
|
userInfo: nil
|
|
|
|
repeats: NO];
|
1999-01-19 12:58:53 +00:00
|
|
|
}
|
1996-07-15 18:42:52 +00:00
|
|
|
|
1999-05-20 19:11:21 +00:00
|
|
|
/*
|
|
|
|
* If we haven't changed anything, we only need to synchronise if
|
|
|
|
* the on-disk database has been changed by someone else.
|
|
|
|
*/
|
1999-09-16 07:21:34 +00:00
|
|
|
if (_changedDomains == NO)
|
1999-05-20 19:11:21 +00:00
|
|
|
{
|
|
|
|
BOOL wantRead = NO;
|
|
|
|
|
1999-09-16 07:21:34 +00:00
|
|
|
if (_lastSync == nil)
|
1999-05-20 19:11:21 +00:00
|
|
|
wantRead = YES;
|
|
|
|
else
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
attr = [mgr fileAttributesAtPath: _defaultsDatabase
|
1999-05-20 19:11:21 +00:00
|
|
|
traverseLink: YES];
|
|
|
|
if (attr == nil)
|
|
|
|
wantRead = YES;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mod = [attr objectForKey: NSFileModificationDate];
|
1999-09-16 07:21:34 +00:00
|
|
|
if ([_lastSync earlierDate: mod] != _lastSync)
|
1999-05-20 19:11:21 +00:00
|
|
|
wantRead = YES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (wantRead == NO)
|
1999-06-24 19:30:29 +00:00
|
|
|
return YES;
|
1999-05-20 19:11:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get file lock - break any lock that is more than five minute old.
|
|
|
|
*/
|
1999-09-16 07:21:34 +00:00
|
|
|
if ([_defaultsDatabaseLock tryLock] == NO)
|
1997-11-03 01:40:03 +00:00
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
if ([[_defaultsDatabaseLock lockDate] timeIntervalSinceNow] < -300.0)
|
1999-02-05 11:44:38 +00:00
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
[_defaultsDatabaseLock breakLock];
|
|
|
|
if ([_defaultsDatabaseLock tryLock] == NO)
|
1999-02-05 11:44:38 +00:00
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
1997-11-03 01:40:03 +00:00
|
|
|
}
|
1996-07-15 18:42:52 +00:00
|
|
|
|
1999-09-16 07:21:34 +00:00
|
|
|
DESTROY(_dictionaryRep);
|
1998-11-30 10:04:24 +00:00
|
|
|
|
1996-07-15 18:42:52 +00:00
|
|
|
// Read the persistent data from the stored database
|
1999-09-16 07:21:34 +00:00
|
|
|
if ([mgr fileExistsAtPath: _defaultsDatabase])
|
1999-02-05 11:44:38 +00:00
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
newDict = [[NSMutableDictionaryClass allocWithZone: [self zone]]
|
1999-09-16 07:21:34 +00:00
|
|
|
initWithContentsOfFile: _defaultsDatabase];
|
1999-10-05 07:02:37 +00:00
|
|
|
if (newDict == nil)
|
|
|
|
{
|
|
|
|
[_defaultsDatabaseLock unlock]; // release file lock
|
|
|
|
NSLog(@"Unable to load defaults from '%@'", _defaultsDatabase);
|
|
|
|
return NO;
|
|
|
|
}
|
1999-02-05 11:44:38 +00:00
|
|
|
}
|
1998-02-09 19:06:40 +00:00
|
|
|
else
|
|
|
|
{
|
1999-05-06 19:37:45 +00:00
|
|
|
attr = [NSDictionary dictionaryWithObjectsAndKeys:
|
2001-06-15 08:49:03 +00:00
|
|
|
NSUserName(), NSFileOwnerAccountName, nil];
|
1999-09-16 07:21:34 +00:00
|
|
|
NSLog(@"Creating defaults database file %@", _defaultsDatabase);
|
|
|
|
[mgr createFileAtPath: _defaultsDatabase
|
1999-05-20 19:11:21 +00:00
|
|
|
contents: nil
|
|
|
|
attributes: attr];
|
1999-09-28 08:48:27 +00:00
|
|
|
newDict = [[NSMutableDictionaryClass allocWithZone: [self zone]]
|
1999-02-05 11:44:38 +00:00
|
|
|
initWithCapacity: 1];
|
1999-09-28 08:48:27 +00:00
|
|
|
[newDict writeToFile: _defaultsDatabase atomically: YES];
|
1999-02-05 11:44:38 +00:00
|
|
|
}
|
1997-10-31 16:26:44 +00:00
|
|
|
|
1999-09-16 07:21:34 +00:00
|
|
|
if (_changedDomains)
|
1997-11-26 21:15:12 +00:00
|
|
|
{ // Synchronize both dictionaries
|
1999-09-28 08:48:27 +00:00
|
|
|
NSEnumerator *enumerator = [_changedDomains objectEnumerator];
|
|
|
|
IMP nextImp;
|
|
|
|
IMP pImp;
|
|
|
|
id obj, dict;
|
1996-07-15 18:42:52 +00:00
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
nextImp = [enumerator methodForSelector: nextObjectSel];
|
|
|
|
pImp = [_persDomains methodForSelector: objectForKeySel];
|
|
|
|
while ((obj = (*nextImp)(enumerator, nextObjectSel)) != nil)
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
dict = (*pImp)(_persDomains, objectForKeySel, obj);
|
|
|
|
if (dict) // Domain was added or changed
|
1999-02-05 11:44:38 +00:00
|
|
|
{
|
|
|
|
[newDict setObject: dict forKey: obj];
|
|
|
|
}
|
1996-07-15 18:42:52 +00:00
|
|
|
else // Domain was removed
|
1999-02-05 11:44:38 +00:00
|
|
|
{
|
|
|
|
[newDict removeObjectForKey: obj];
|
|
|
|
}
|
1996-07-15 18:42:52 +00:00
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
RELEASE(_persDomains);
|
|
|
|
_persDomains = newDict;
|
1996-07-15 18:42:52 +00:00
|
|
|
// Save the changes
|
1999-09-16 07:21:34 +00:00
|
|
|
if (![_persDomains writeToFile: _defaultsDatabase atomically: YES])
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
[_defaultsDatabaseLock unlock];
|
1996-07-15 18:42:52 +00:00
|
|
|
return NO;
|
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
attr = [mgr fileAttributesAtPath: _defaultsDatabase
|
1999-05-20 19:11:21 +00:00
|
|
|
traverseLink: YES];
|
|
|
|
mod = [attr objectForKey: NSFileModificationDate];
|
1999-09-16 07:21:34 +00:00
|
|
|
ASSIGN(_lastSync, mod);
|
|
|
|
[_defaultsDatabaseLock unlock]; // release file lock
|
1996-07-15 18:42:52 +00:00
|
|
|
}
|
|
|
|
else
|
1999-01-19 12:58:53 +00:00
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
attr = [mgr fileAttributesAtPath: _defaultsDatabase
|
1999-05-20 19:11:21 +00:00
|
|
|
traverseLink: YES];
|
|
|
|
mod = [attr objectForKey: NSFileModificationDate];
|
1999-09-16 07:21:34 +00:00
|
|
|
ASSIGN(_lastSync, mod);
|
|
|
|
[_defaultsDatabaseLock unlock]; // release file lock
|
|
|
|
if ([_persDomains isEqual: newDict] == NO)
|
1999-01-19 12:58:53 +00:00
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
RELEASE(_persDomains);
|
|
|
|
_persDomains = newDict;
|
1999-01-19 12:58:53 +00:00
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
postNotificationName: NSUserDefaultsDidChangeNotification
|
|
|
|
object: nil];
|
|
|
|
}
|
|
|
|
else
|
1999-02-05 11:44:38 +00:00
|
|
|
{
|
1999-05-20 19:11:21 +00:00
|
|
|
RELEASE(newDict);
|
1999-02-05 11:44:38 +00:00
|
|
|
}
|
1996-07-15 18:42:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
*** Maintaining Volatile Domains
|
|
|
|
*************************************************************************/
|
1999-09-28 08:48:27 +00:00
|
|
|
- (void) removeVolatileDomainForName: (NSString*)domainName
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
DESTROY(_dictionaryRep);
|
|
|
|
[_tempDomains removeObjectForKey: domainName];
|
1996-07-15 18:42:52 +00:00
|
|
|
}
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
- (void) setVolatileDomain: (NSDictionary*)domain
|
|
|
|
forName: (NSString*)domainName
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
id dict = [_persDomains objectForKey: domainName];
|
1996-07-15 18:42:52 +00:00
|
|
|
|
|
|
|
if (dict)
|
|
|
|
{
|
1999-05-06 19:37:45 +00:00
|
|
|
[NSException raise: NSInvalidArgumentException
|
1999-09-28 08:48:27 +00:00
|
|
|
format: @"Volatile domain %@ already exists", domainName];
|
1996-07-15 18:42:52 +00:00
|
|
|
return;
|
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
DESTROY(_dictionaryRep);
|
1999-09-28 08:48:27 +00:00
|
|
|
domain = [domain mutableCopy];
|
1999-09-16 07:21:34 +00:00
|
|
|
[_tempDomains setObject: domain forKey: domainName];
|
1999-09-28 08:48:27 +00:00
|
|
|
RELEASE(domain);
|
1996-07-15 18:42:52 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
- (NSDictionary*) volatileDomainForName: (NSString*)domainName
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
return AUTORELEASE([[_tempDomains objectForKey: domainName] copy]);
|
1996-07-15 18:42:52 +00:00
|
|
|
}
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
- (NSArray*) volatileDomainNames
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
return [_tempDomains allKeys];
|
1996-07-15 18:42:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
*** Making Advanced Use of Defaults
|
|
|
|
*************************************************************************/
|
1999-09-28 08:48:27 +00:00
|
|
|
- (NSDictionary*) dictionaryRepresentation
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
if (_dictionaryRep == nil)
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1998-11-30 10:04:24 +00:00
|
|
|
NSEnumerator *enumerator;
|
|
|
|
NSMutableDictionary *dictRep;
|
1999-09-28 08:48:27 +00:00
|
|
|
id obj;
|
|
|
|
id dict;
|
|
|
|
IMP nImp;
|
|
|
|
IMP pImp;
|
|
|
|
IMP tImp;
|
2000-10-30 18:00:27 +00:00
|
|
|
IMP addImp;
|
1998-11-30 10:04:24 +00:00
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
pImp = [_persDomains methodForSelector: objectForKeySel];
|
|
|
|
tImp = [_tempDomains methodForSelector: objectForKeySel];
|
|
|
|
|
1999-09-16 07:21:34 +00:00
|
|
|
enumerator = [_searchList reverseObjectEnumerator];
|
1999-09-28 08:48:27 +00:00
|
|
|
nImp = [enumerator methodForSelector: nextObjectSel];
|
|
|
|
|
|
|
|
dictRep = [NSMutableDictionaryClass allocWithZone: NSDefaultMallocZone()];
|
1998-11-30 10:04:24 +00:00
|
|
|
dictRep = [dictRep initWithCapacity: 512];
|
2000-10-30 18:00:27 +00:00
|
|
|
addImp = [dictRep methodForSelector: addSel];
|
1999-09-28 08:48:27 +00:00
|
|
|
|
|
|
|
while ((obj = (*nImp)(enumerator, nextObjectSel)) != nil)
|
1998-11-30 10:04:24 +00:00
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
if ( (dict = (*pImp)(_persDomains, objectForKeySel, obj)) != nil
|
|
|
|
|| (dict = (*tImp)(_tempDomains, objectForKeySel, obj)) != nil)
|
2000-10-30 18:00:27 +00:00
|
|
|
(*addImp)(dictRep, addSel, dict);
|
1998-11-30 10:04:24 +00:00
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
_dictionaryRep = [dictRep copy];
|
1999-05-20 19:11:21 +00:00
|
|
|
RELEASE(dictRep);
|
1996-07-15 18:42:52 +00:00
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
return _dictionaryRep;
|
1996-07-15 18:42:52 +00:00
|
|
|
}
|
|
|
|
|
1998-11-30 10:04:24 +00:00
|
|
|
- (void) registerDefaults: (NSDictionary*)newVals
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1998-11-30 10:04:24 +00:00
|
|
|
NSMutableDictionary *regDefs;
|
|
|
|
|
1999-09-16 07:21:34 +00:00
|
|
|
regDefs = [_tempDomains objectForKey: NSRegistrationDomain];
|
1998-11-30 10:04:24 +00:00
|
|
|
if (regDefs == nil)
|
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
regDefs = [NSMutableDictionaryClass
|
|
|
|
dictionaryWithCapacity: [newVals count]];
|
2001-06-15 08:49:03 +00:00
|
|
|
[_tempDomains setObject: regDefs forKey: NSRegistrationDomain];
|
1998-11-30 10:04:24 +00:00
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
DESTROY(_dictionaryRep);
|
1998-11-30 10:04:24 +00:00
|
|
|
[regDefs addEntriesFromDictionary: newVals];
|
1996-07-15 18:42:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
|
|
*** Accessing the User Defaults database
|
|
|
|
*************************************************************************/
|
1999-09-28 08:48:27 +00:00
|
|
|
- (void) __createStandardSearchList
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
2001-02-22 07:36:05 +00:00
|
|
|
NSArray *uL;
|
|
|
|
NSEnumerator *enumerator;
|
1999-09-28 08:48:27 +00:00
|
|
|
id object;
|
1996-07-15 18:42:52 +00:00
|
|
|
|
|
|
|
// Note: The search list should exist!
|
|
|
|
|
|
|
|
// 1. NSArgumentDomain
|
1999-09-16 07:21:34 +00:00
|
|
|
[_searchList addObject: NSArgumentDomain];
|
1996-07-15 18:42:52 +00:00
|
|
|
|
|
|
|
// 2. Application
|
1999-09-16 07:21:34 +00:00
|
|
|
[_searchList addObject: processName];
|
1996-07-15 18:42:52 +00:00
|
|
|
|
2000-10-27 15:54:35 +00:00
|
|
|
// 3. NSGlobalDomain
|
|
|
|
[_searchList addObject: NSGlobalDomain];
|
|
|
|
|
|
|
|
// 4. User's preferred languages
|
2001-02-22 07:36:05 +00:00
|
|
|
uL = [[self class] userLanguages];
|
|
|
|
enumerator = [uL objectEnumerator];
|
1996-07-15 18:42:52 +00:00
|
|
|
while ((object = [enumerator nextObject]))
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
[_searchList addObject: object];
|
1996-07-15 18:42:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 5. NSRegistrationDomain
|
1999-09-16 07:21:34 +00:00
|
|
|
[_searchList addObject: NSRegistrationDomain];
|
1996-07-15 18:42:52 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
- (NSDictionary*) __createArgumentDictionary
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
NSArray *args = [[NSProcessInfo processInfo] arguments];
|
1999-09-16 07:21:34 +00:00
|
|
|
//$$$ NSArray *args = _searchList; // $$$
|
1999-09-28 08:48:27 +00:00
|
|
|
NSEnumerator *enumerator = [args objectEnumerator];
|
1996-07-15 18:42:52 +00:00
|
|
|
NSMutableDictionary *argDict =
|
1999-09-28 08:48:27 +00:00
|
|
|
[NSMutableDictionaryClass dictionaryWithCapacity: 2];
|
|
|
|
BOOL done;
|
|
|
|
id key, val;
|
1996-07-15 18:42:52 +00:00
|
|
|
|
1999-02-17 09:32:02 +00:00
|
|
|
[enumerator nextObject]; // Skip process name.
|
1996-07-15 18:42:52 +00:00
|
|
|
done = ((key = [enumerator nextObject]) == nil);
|
|
|
|
|
|
|
|
while (!done)
|
|
|
|
{
|
1999-09-03 08:59:07 +00:00
|
|
|
if ([key hasPrefix: @"-"])
|
|
|
|
{
|
|
|
|
NSString *old = nil;
|
2001-08-01 10:59:58 +00:00
|
|
|
|
1999-09-03 08:59:07 +00:00
|
|
|
/* anything beginning with a '-' is a defaults key and we must strip
|
|
|
|
the '-' from it. As a special case, we leave the '- in place
|
|
|
|
for '-GS...' and '--GS...' for backward compatibility. */
|
|
|
|
if ([key hasPrefix: @"-GS"] == YES || [key hasPrefix: @"--GS"] == YES)
|
|
|
|
{
|
|
|
|
old = key;
|
|
|
|
}
|
1998-01-02 18:09:52 +00:00
|
|
|
key = [key substringFromIndex: 1];
|
1999-09-03 08:59:07 +00:00
|
|
|
val = [enumerator nextObject];
|
2001-08-01 10:59:58 +00:00
|
|
|
if (val == nil)
|
1999-09-03 08:59:07 +00:00
|
|
|
{ // No more args
|
|
|
|
[argDict setObject: @"" forKey: key]; // arg is empty.
|
2001-08-01 10:59:58 +00:00
|
|
|
if (old != nil)
|
|
|
|
{
|
|
|
|
[argDict setObject: @"" forKey: old];
|
|
|
|
}
|
1999-09-03 08:59:07 +00:00
|
|
|
done = YES;
|
|
|
|
continue;
|
|
|
|
}
|
2001-08-01 10:59:58 +00:00
|
|
|
else if ([val hasPrefix: @"-"] == YES)
|
1999-09-03 08:59:07 +00:00
|
|
|
{ // Yet another argument
|
|
|
|
[argDict setObject: @"" forKey: key]; // arg is empty.
|
2001-08-01 10:59:58 +00:00
|
|
|
if (old != nil)
|
|
|
|
{
|
|
|
|
[argDict setObject: @"" forKey: old];
|
|
|
|
}
|
1999-09-03 08:59:07 +00:00
|
|
|
key = val;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // Real parameter
|
2001-08-24 11:36:40 +00:00
|
|
|
/* Parsing the argument as a property list is very
|
|
|
|
delicate. We *MUST NOT* crash here just because a
|
|
|
|
strange parameter (such as `(load "test.scm")`) is
|
|
|
|
passed, otherwise the whole library is useless in a
|
|
|
|
foreign environment. */
|
|
|
|
NSObject *plist_val;
|
|
|
|
|
|
|
|
NS_DURING
|
|
|
|
{
|
|
|
|
plist_val = [val propertyList];
|
|
|
|
}
|
|
|
|
NS_HANDLER
|
|
|
|
{
|
|
|
|
plist_val = val;
|
|
|
|
}
|
|
|
|
NS_ENDHANDLER
|
|
|
|
|
|
|
|
/* Make sure we don't crash being caught adding nil to
|
|
|
|
a dictionary. */
|
|
|
|
if (plist_val == nil)
|
|
|
|
{
|
|
|
|
plist_val = val;
|
|
|
|
}
|
|
|
|
|
|
|
|
[argDict setObject: plist_val forKey: key];
|
2001-08-01 10:59:58 +00:00
|
|
|
if (old != nil)
|
|
|
|
{
|
2001-08-24 11:36:40 +00:00
|
|
|
[argDict setObject: plist_val forKey: old];
|
2001-08-01 10:59:58 +00:00
|
|
|
}
|
1999-09-03 08:59:07 +00:00
|
|
|
}
|
1998-01-02 18:09:52 +00:00
|
|
|
}
|
1996-07-15 18:42:52 +00:00
|
|
|
done = ((key = [enumerator nextObject]) == nil);
|
|
|
|
}
|
|
|
|
|
|
|
|
return argDict;
|
|
|
|
}
|
|
|
|
|
1999-09-28 08:48:27 +00:00
|
|
|
- (void) __changePersistentDomain: (NSString*)domainName
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-28 08:48:27 +00:00
|
|
|
NSEnumerator *enumerator = nil;
|
|
|
|
IMP nImp;
|
|
|
|
id obj;
|
1998-11-30 10:04:24 +00:00
|
|
|
|
1999-09-16 07:21:34 +00:00
|
|
|
DESTROY(_dictionaryRep);
|
|
|
|
if (!_changedDomains)
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
_changedDomains = [[NSMutableArray alloc] initWithCapacity: 5];
|
1996-07-15 18:42:52 +00:00
|
|
|
[[NSNotificationCenter defaultCenter]
|
1999-05-06 19:37:45 +00:00
|
|
|
postNotificationName: NSUserDefaultsDidChangeNotification object: nil];
|
1996-07-15 18:42:52 +00:00
|
|
|
}
|
|
|
|
|
1999-09-16 07:21:34 +00:00
|
|
|
enumerator = [_changedDomains objectEnumerator];
|
1999-09-28 08:48:27 +00:00
|
|
|
nImp = [enumerator methodForSelector: nextObjectSel];
|
|
|
|
while ((obj = (*nImp)(enumerator, nextObjectSel)) != nil)
|
1996-07-15 18:42:52 +00:00
|
|
|
{
|
1999-05-06 19:37:45 +00:00
|
|
|
if ([obj isEqualToString: domainName])
|
1996-07-15 18:42:52 +00:00
|
|
|
return;
|
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
[_changedDomains addObject: domainName];
|
1996-07-15 18:42:52 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1999-01-19 12:58:53 +00:00
|
|
|
- (void) __timerTicked: (NSTimer*)tim
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
if (tim == _tickingTimer)
|
|
|
|
_tickingTimer = nil;
|
1999-01-19 12:58:53 +00:00
|
|
|
|
|
|
|
[self synchronize];
|
|
|
|
}
|
1996-07-15 18:42:52 +00:00
|
|
|
@end
|