TimeZone patch from wacko

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@2615 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Adam Fedor 1997-11-03 14:30:13 +00:00
parent d0bfdd58a1
commit c927c0cb37
4 changed files with 366 additions and 122 deletions

View file

@ -1,3 +1,9 @@
Sun Nov 2 15:47:10 1997 Yoo C. Chung <wacko@laplace.snu.ac.kr>
* src/NSTimeZone.m: More effecient implementation of [NSTimeZone
-abbreviationDictionary] object enumerator.
More robust error logging. Description method changes.
Sat Nov 1 06:45:00 1997 Richard Frith-Macdonald <richard@brainstorm.co.uk>
* src/NSDistributedLock: New OPENSTEP class implementation.

View file

@ -0,0 +1,48 @@
/* Interface for NSDistributedLock for GNUStep
Copyright (C) 1997 Free Software Foundation, Inc.
Written by: Richard Frith-Macdonald <richard@brainstorm.co.uk>
Date: 1997
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 __NSDistributedLock_h_GNUSTEP_BASE_INCLUDE
#define __NSDistributedLock_h_GNUSTEP_BASE_INCLUDE
#include <Foundation/NSObject.h>
#include <Foundation/NSString.h>
#include <Foundation/NSDate.h>
@interface NSDistributedLock : NSObject
{
NSString *lockPath;
NSDate *lockTime;
}
+ (NSDistributedLock*)lockWithPath: (NSString*)aPath;
- (NSDistributedLock*)initWithPath: (NSString*)aPath;
- (void)breakLock;
- (NSDate*)lockDate;
- (BOOL)tryLock;
- (void)unlock;
@end
#endif /* __NSDistributedLock_h_GNUSTEP_BASE_INCLUDE */

175
Source/NSDistributedLock.m Normal file
View file

@ -0,0 +1,175 @@
/* Implementation for GNU Objective-C version of NSDistributedLock
Copyright (C) 1997 Free Software Foundation, Inc.
Written by: Richard Frith-Macdonald <richard@brainstorm.co.uk>
Created: November 1997
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 <Foundation/NSDistributedLock.h>
#include <Foundation/NSFileManager.h>
#include <Foundation/NSException.h>
#include <Foundation/NSValue.h>
#include <Foundation/NSDebug.h>
#include <fcntl.h>
@implementation NSDistributedLock
+ (NSDistributedLock*)lockWithPath: (NSString*)aPath
{
return [[[self alloc] initWithPath: aPath] autorelease];
}
- (void)breakLock
{
NSFileManager *fileManager;
fileManager = [NSFileManager defaultManager];
if ([fileManager removeFileAtPath: lockPath handler: nil] == NO)
[NSException raise: NSGenericException
format: @"Failed to remove lock directory '%@' - %s",
lockPath, strerror(errno)];
[lockTime release];
lockTime = nil;
}
- (void)dealloc
{
[lockPath release];
[lockTime release];
[super dealloc];
}
- (NSDistributedLock*)initWithPath: (NSString*)aPath
{
NSFileManager *fileManager;
NSString *lockDir;
BOOL isDirectory;
lockPath = [aPath copy];
lockTime = nil;
fileManager = [NSFileManager defaultManager];
lockDir = [lockPath stringByDeletingLastPathComponent];
if ([fileManager fileExistsAtPath: lockDir isDirectory: &isDirectory] == NO)
{
NSLog(@"part of the path to the lock file '%@' is missing\n", lockPath);
[self dealloc];
return nil;
}
if (isDirectory == NO)
{
NSLog(@"part of the path to the lock file '%@' is not a directory\n",
lockPath);
[self dealloc];
return nil;
}
if ([fileManager isWritableFileAtPath: lockDir] == NO)
{
NSLog(@"parent directory of lock file '%@' is not writable\n", lockPath);
[self dealloc];
return nil;
}
if ([fileManager isExecutableFileAtPath: lockDir] == NO)
{
NSLog(@"parent directory of lock file '%@' is not accessible\n",
lockPath);
[self dealloc];
return nil;
}
return self;
}
- (NSDate*)lockDate
{
NSFileManager *fileManager;
NSDictionary *attributes;
fileManager = [NSFileManager defaultManager];
attributes = [fileManager fileAttributesAtPath: lockPath traverseLink: YES];
return [attributes objectForKey: NSFileModificationDate];
}
- (BOOL)tryLock
{
NSFileManager *fileManager;
NSMutableDictionary *attributes;
fileManager = [NSFileManager defaultManager];
attributes = [NSMutableDictionary dictionaryWithCapacity: 1];
[attributes setObject: [NSNumber numberWithUnsignedInt: 0755]
forKey: NSFilePosixPermissions];
if ([fileManager createDirectoryAtPath: lockPath
attributes: attributes] == NO)
{
BOOL dir;
if ([fileManager fileExistsAtPath: lockPath isDirectory: &dir] == NO)
[NSException raise: NSGenericException
format: @"Failed to create lock directory '%@' - %s",
lockPath, strerror(errno)];
[lockTime release];
lockTime = nil;
return NO;
}
else
{
NSFileManager *fileManager;
NSDictionary *attributes;
fileManager = [NSFileManager defaultManager];
attributes = [fileManager fileAttributesAtPath: lockPath
traverseLink: YES];
[lockTime release];
lockTime = [[attributes objectForKey: NSFileModificationDate] retain];
return YES;
}
}
- (void)unlock
{
NSFileManager *fileManager;
NSDictionary *attributes;
if (lockTime == nil)
[NSException raise: NSGenericException format: @"not locked by us"];
/*
* Don't remove the lock if it has already been broken by someone
* else and re-created. Unfortunately, there is a window between
* testing and removing, but we do the bset we can.
*/
fileManager = [NSFileManager defaultManager];
attributes = [fileManager fileAttributesAtPath: lockPath traverseLink: YES];
if ([lockTime isEqual: [attributes objectForKey: NSFileModificationDate]])
{
if ([fileManager removeFileAtPath: lockPath handler: nil] == NO)
[NSException raise: NSGenericException
format: @"Failed to remove lock directory '%@' - %s",
lockPath, strerror(errno)];
}
else
NSLog(@"lock '%@' already broken and in use again\n", lockPath);
[lockTime release];
lockTime = nil;
}
@end

View file

@ -28,7 +28,9 @@
We do not use a dictionary for storing time zones, since such a
dictionary would be VERY large (~500K). And we would have to use a
complicated object determining whether we're using daylight savings
time and such for every entry in the dictionary.
time and such for every entry in the dictionary. (Though we will
eventually have to change the implementation to prevent the year
2038 problem.)
The local time zone can be specified with the user defaults
database, the TZ environment variable, the file LOCAL_TIME_FILE, or
@ -76,7 +78,7 @@
/* File holding regions grouped by latitude. It is a text file with
each line comprised of the latitude region, whitespace, and the
name. Neither the abbreviation not the name can contain
name. Neither the abbreviation nor the name can contain
whitespace, and each line must not be longer than 80 characters. */
#define REGIONS_FILE @"regions"
@ -84,17 +86,7 @@
#define LOCAL_TIME_FILE @"localtime"
/* Directory that contains the actual time zones. */
#define ZONES_DIR @"zones/"
/* Private methods */
@interface NSTimeZone (Private)
+ (NSString *)getAbbreviationFile;
+ (NSString *)getRegionsFile;
+ (NSString *)getLocalTimeFile;
+ (NSString *)getTimeZoneFile: (NSString *)name;
@end
#define ZONES_DIR "zones/"
@class NSInternalTimeTransition;
@ -146,6 +138,16 @@ decode (const void *ptr)
}
/* Object enumerator for NSInternalAbbrevDict. */
@interface NSInternalAbbrevDictObjectEnumerator : NSEnumerator
{
NSEnumerator *dict_enum;
}
- initWithDict: (NSDictionary*)aDict;
@end
/* Front end that actually uses [NSTimeZone abbrebiationMap]. */
@interface NSInternalAbbrevDict : NSDictionary
@end
@ -182,9 +184,7 @@ decode (const void *ptr)
int offset; // Offset from UTC in seconds.
}
+ timeZoneWithOffset: (int)anOffset;
- initWithOffset: (int)anOffset withName: (NSString*)aName;
- initWithOffset: (int)anOffset;
@end
@ -200,19 +200,54 @@ decode (const void *ptr)
withOffset: (int)anOffset withDST: (BOOL)isDST;
@end
/* Private methods for obtaining resource file names. */
@interface NSTimeZone (Private)
+ (NSString*)getAbbreviationFile;
+ (NSString*)getRegionsFile;
+ (NSString*)getLocalTimeFile;
+ (NSString*)getTimeZoneFile: (NSString*)name;
@end
@implementation NSInternalAbbrevDictObjectEnumerator
- (void)dealloc
{
[dict_enum release];
}
- initWithDict: (NSDictionary*)aDict
{
dict_enum = [[aDict objectEnumerator] retain];
return self;
}
- nextObject
{
id object;
object = [dict_enum nextObject];
if (object != nil)
return [object objectAtIndex: 0];
else
return nil;
}
@end
@implementation NSInternalAbbrevDict
+ allocWithZone: (NSZone*)zone
{
return NSAllocateObject(self, 0, zone);
}
- init
{
return self;
}
- (unsigned)count
{
return [[NSTimeZone abbreviationMap] count];
@ -222,18 +257,12 @@ decode (const void *ptr)
{
return [[NSTimeZone abbreviationMap] keyEnumerator];
}
- (NSEnumerator*)objectEnumerator
{
/* FIXME: this is a memory hungry implementation */
id e, name, a;
a = [NSMutableArray array];
e = [[NSTimeZone abbreviationMap] keyEnumerator];
while ((name = [e nextObject]) != nil)
[a addObject: [[[NSTimeZone abbreviationMap] objectForKey: name]
objectAtIndex: 0]];
return [a objectEnumerator];
return [[[NSInternalAbbrevDictObjectEnumerator alloc]
initWithDict: [NSTimeZone abbreviationMap]]
autorelease];
}
- objectForKey: key
@ -242,7 +271,7 @@ decode (const void *ptr)
}
@end
@implementation NSInternalTimeTransition
@ -260,12 +289,12 @@ decode (const void *ptr)
detail_index = anIndex;
return self;
}
- (int)transTime
{
return trans_time;
}
- (char)detailIndex
{
return detail_index;
@ -285,7 +314,7 @@ decode (const void *ptr)
details = [zoneDetails retain];
return self;
}
- (void)dealloc
{
[name release];
@ -293,7 +322,7 @@ decode (const void *ptr)
[details release];
[super dealloc];
}
- (void)encodeWithCoder: aCoder
{
[super encodeWithCoder: aCoder];
@ -306,14 +335,7 @@ decode (const void *ptr)
self = [super initWithCoder: aDecoder];
return (self = (id)[NSTimeZone timeZoneWithName: [aDecoder decodeObject]]);
}
- (NSString*)description
{
return [NSString
stringWithFormat: @"%@(%@, %@)",
[self class], transitions, details];
}
- (NSTimeZoneDetail*)timeZoneDetailForDate: (NSDate*)date
{
unsigned index;
@ -363,45 +385,31 @@ decode (const void *ptr)
@implementation NSConcreteAbsoluteTimeZone
+ timeZoneWithOffset: (int)anOffset
{
id newName, zone;
newName = [NSString stringWithFormat: @"%d", anOffset];
zone = [zoneDictionary objectForKey: newName];
if (zone == nil)
{
zone = [[self alloc] initWithOffset: anOffset withName: newName];
[zoneDictionary setObject: zone forKey: newName];
}
return zone;
}
- initWithOffset: (int)anOffset withName: (NSString*)aName
- initWithOffset: (int)anOffset
{
[super init];
name = [aName retain];
name = [NSString stringWithFormat: @"%d", anOffset];
detail = [[NSConcreteTimeZoneDetail alloc]
initWithTimeZone: self withAbbrev: name
withOffset: offset withDST: NO];
initWithTimeZone: self withAbbrev: name
withOffset: offset withDST: NO];
offset = anOffset;
return self;
}
- (void)dealloc
{
[name release];
[detail release];
[super dealloc];
}
- (void)encodeWithCoder: aCoder
{
[super encodeWithCoder: aCoder];
[aCoder encodeObject: name];
}
- initWithCoder: aDecoder
{
self = [super initWithCoder: aDecoder];
@ -409,12 +417,7 @@ decode (const void *ptr)
offset = [name intValue];
return self;
}
- (NSString*)description
{
return [NSString stringWithFormat: @"%@(%d)", [self class], offset];
}
- (NSTimeZoneDetail*)timeZoneDetailForDate: (NSDate*)date
{
return detail;
@ -448,10 +451,11 @@ decode (const void *ptr)
- (void)dealloc
{
[timeZone release];
[abbrev release];
[super dealloc];
}
- (void)encodeWithCoder: aCoder
{
[super encodeWithCoder: aCoder];
@ -459,7 +463,7 @@ decode (const void *ptr)
[aCoder encodeValueOfObjCType: @encode(int) at: &offset];
[aCoder encodeValueOfObjCType: @encode(BOOL) at: &is_dst];
}
- initWithCoder: aDecoder
{
self = [super initWithCoder: aDecoder];
@ -473,7 +477,7 @@ decode (const void *ptr)
{
return [timeZone timeZoneDetailForDate: date];
}
- (NSString*)timeZoneName
{
return [timeZone timeZoneName];
@ -484,14 +488,6 @@ decode (const void *ptr)
return [timeZone timeZoneDetailArray];
}
- (NSString*)description
{
return [NSString
stringWithFormat: @"%@(%@, %@, %d, %d)",
[self class], [timeZone timeZoneName],
abbrev, offset, (int)is_dst];
}
- (BOOL)isDaylightSavingTimeZone
{
return is_dst;
@ -519,6 +515,7 @@ decode (const void *ptr)
id localZoneString = nil;
zone_mutex = [NSLock new];
zoneDictionary = [[NSMutableDictionary alloc] init];
localZoneString = [[NSUserDefaults standardUserDefaults]
stringForKey: @LOCALDBKEY];
@ -543,8 +540,6 @@ decode (const void *ptr)
fclose(fp);
}
}
else
NSLog(@"NSTimeZone unable to find the `%@' file.", LOCAL_TIME_FILE);
}
if (localZoneString != nil)
localTimeZone = [NSTimeZone timeZoneWithName: localZoneString];
@ -556,17 +551,19 @@ decode (const void *ptr)
course). */
if (localTimeZone == nil)
{
NSLog(@"Local time zone either not specified or incorrect.");
NSLog(@"Using time zone with absolute offset 0.");
localTimeZone = [NSTimeZone timeZoneForSecondsFromGMT: 0];
}
fake_abbrev_dict = [[NSInternalAbbrevDict alloc] init];
zoneDictionary = [[NSMutableDictionary alloc] init];
[zoneDictionary setObject: localTimeZone
forKey: [localTimeZone timeZoneName]];
}
}
- (NSString*)description
{
return [self timeZoneName];
}
+ (NSTimeZoneDetail*)defaultTimeZone
{
return [localTimeZone timeZoneDetailForDate: [NSDate date]];
@ -582,7 +579,7 @@ decode (const void *ptr)
/* We simply return the following because an existing time zone with
the given offset might not always have the same offset (daylight
savings time, change in standard time, etc.). */
return [NSConcreteAbsoluteTimeZone timeZoneWithOffset: seconds];
return [[NSConcreteAbsoluteTimeZone alloc] initWithOffset: seconds];
}
+ (NSTimeZoneDetail*)timeZoneWithAbbreviation: (NSString*)abbreviation
@ -608,20 +605,21 @@ decode (const void *ptr)
database. */
[NSException
raise: NSInternalInconsistencyException
format: @"Time zone abbreviation %@ inconsistent", abbreviation];
format: @"Time zone abbreviation `%@' inconsistent.", abbreviation];
return nil;
}
+ (NSTimeZone*)timeZoneWithName: (NSString*)aTimeZoneName
{
static NSString *fileException = @"fileException";
static NSString *errMess = @"File read error in NSTimeZone.";
id zone, transArray, detailsArray;
int i, n_trans, n_types, names_size;
id *abbrevsArray;
char *trans, *type_idxs, *zone_abbrevs;
struct tzhead header;
struct ttinfo *types; // Temporary array for details
FILE *file;
FILE *file = NULL;
NSString *fileName;
[zone_mutex lock];
@ -638,14 +636,7 @@ decode (const void *ptr)
|| ([aTimeZoneName cStringNoCopy])[0] == '/'
|| strchr([aTimeZoneName cStringNoCopy], '.') != NULL)
{
[zone_mutex unlock];
return nil;
}
fileName = [NSTimeZone getTimeZoneFile: aTimeZoneName];
file = fopen([fileName cStringNoCopy], "rb");
if (file == NULL)
{
NSLog(@"Disallowed time zone name `%@'.", aTimeZoneName);
[zone_mutex unlock];
return nil;
}
@ -653,9 +644,15 @@ decode (const void *ptr)
NS_DURING
zone = [NSConcreteTimeZone alloc];
/* Open file. */
fileName = [NSTimeZone getTimeZoneFile: aTimeZoneName];
file = fopen([fileName cStringNoCopy], "rb");
if (file == NULL)
[NSException raise: fileException format: errMess];
/* Read header. */
if (fread(&header, sizeof(struct tzhead), 1, file) != 1)
[NSException raise: fileException format: nil];
[NSException raise: fileException format: errMess];
n_trans = decode(header.tzh_timecnt);
n_types = decode(header.tzh_typecnt);
@ -666,8 +663,8 @@ decode (const void *ptr)
type_idxs = NSZoneMalloc(NSDefaultMallocZone(), n_trans);
if (fread(trans, 4, n_trans, file) != n_trans
|| fread(type_idxs, 1, n_trans, file) != n_trans)
[NSException raise: fileException format: nil];
transArray = [NSMutableArray array];
[NSException raise: fileException format: errMess];
transArray = [[NSMutableArray alloc] initWithCapacity: n_trans];
for (i = 0; i < n_trans; i++)
[transArray
addObject: [[NSInternalTimeTransition alloc]
@ -686,14 +683,14 @@ decode (const void *ptr)
if (fread(x, 1, 4, file) != 4
|| fread(&types[i].isdst, 1, 1, file) != 1
|| fread(&types[i].abbr_idx, 1, 1, file) != 1)
[NSException raise: fileException format: nil];
[NSException raise: fileException format: errMess];
types[i].offset = decode(x);
}
/* Read in time zone abbreviation strings. */
zone_abbrevs = NSZoneMalloc(NSDefaultMallocZone(), names_size);
if (fread(zone_abbrevs, 1, names_size, file) != names_size)
[NSException raise: fileException format: nil];
[NSException raise: fileException format: errMess];
abbrevsArray = NSZoneMalloc(NSDefaultMallocZone(), sizeof(id)*names_size);
i = 0;
while (i < names_size)
@ -704,7 +701,7 @@ decode (const void *ptr)
NSZoneFree(NSDefaultMallocZone(), zone_abbrevs);
/* Create time zone details. */
detailsArray = [[NSMutableArray alloc] init];
detailsArray = [[NSMutableArray alloc] initWithCapacity: n_types];
for (i = 0; i < n_types; i++)
[detailsArray
addObject: [[NSConcreteTimeZoneDetail alloc]
@ -714,17 +711,21 @@ decode (const void *ptr)
withDST: (types[i].isdst > 0)]];
NSZoneFree(NSDefaultMallocZone(), abbrevsArray);
NSZoneFree(NSDefaultMallocZone(), types);
[zone initWithName: [aTimeZoneName copy] withTransitions: transArray
withDetails: detailsArray];
withDetails: detailsArray];
[zoneDictionary setObject: zone forKey: aTimeZoneName];
fclose(file);
NS_HANDLER
if (zone != nil)
[zone release];
if ([localException name] != fileException)
[localException raise];
fclose(file);
zone = nil;
NSLog(@"Unable to obtain time zone `%@'.", aTimeZoneName);
NS_ENDHANDLER
if (file != NULL)
fclose(file);
[zone_mutex unlock];
return zone;
}
@ -738,7 +739,7 @@ decode (const void *ptr)
{
if (aTimeZone == nil)
[NSException raise: NSInvalidArgumentException
format: @"Nil time zone specified"];
format: @"Nil time zone specified."];
[localTimeZone release];
localTimeZone = [aTimeZone retain];
}
@ -768,8 +769,9 @@ decode (const void *ptr)
fileName = [NSTimeZone getAbbreviationFile];
file = fopen([fileName cStringNoCopy], "r");
if (file == NULL)
[NSException raise: NSInternalInconsistencyException
format: @"Failed to open time zone abbreviation dictionary"];
[NSException
raise: NSInternalInconsistencyException
format: @"Failed to open time zone abbreviation dictionary."];
while (fscanf(file, "%79s %79s", abbrev, name) == 2)
{
id a, the_name, the_abbrev;
@ -788,12 +790,12 @@ decode (const void *ptr)
return abbreviationDictionary;
}
- (NSString*)timeZoneName
{
return [self subclassResponsibility: _cmd];
}
+ (NSArray*)timeZoneArray
{
/* We create the array only when we need it to reduce overhead. */
@ -814,25 +816,36 @@ decode (const void *ptr)
fileName = [NSTimeZone getRegionsFile];
file = fopen([fileName cStringNoCopy], "r");
if (file == NULL)
[NSException raise: NSInternalInconsistencyException
format: @"Failed to open regions array file"];
[NSException
raise: NSInternalInconsistencyException
format: @"Failed to open time zone regions array file."];
while (fscanf(file, "%d %s", &index, name) == 2)
[temp_array[index] addObject: [[NSString alloc] initWithCString: name]];
fclose(file);
regionsArray = [[NSArray alloc] initWithObjects: temp_array count: 24];
return regionsArray;
}
- (NSArray*)timeZoneDetailArray
{
return [self subclassResponsibility: _cmd];
}
@end
@implementation NSTimeZoneDetail
- (NSString*)description
{
return [NSString
stringWithFormat: @"%@(%@, %s%d)",
[self timeZoneName],
[self timeZoneAbbreviation],
([self isDaylightSavingTimeZone]? "IS_DST, ": ""),
[self timeZoneSecondsFromGMT]];
}
- (BOOL)isDaylightSavingTimeZone
{
[self subclassResponsibility: _cmd];
@ -852,33 +865,35 @@ decode (const void *ptr)
@end
@implementation NSTimeZone (Private)
+ (NSString *)getAbbreviationFile
+ (NSString*)getAbbreviationFile
{
return [NSBundle pathForGNUstepResource: ABBREV_DICT
ofType: @""
inDirectory: TIME_ZONE_DIR];
}
+ (NSString *)getRegionsFile
+ (NSString*)getRegionsFile
{
return [NSBundle pathForGNUstepResource: REGIONS_FILE
ofType: @""
inDirectory: TIME_ZONE_DIR];
}
+ (NSString *)getLocalTimeFile
+ (NSString*)getLocalTimeFile
{
return [NSBundle pathForGNUstepResource: LOCAL_TIME_FILE
ofType: @""
inDirectory: TIME_ZONE_DIR];
}
+ (NSString *)getTimeZoneFile: (NSString *)name
+ (NSString*)getTimeZoneFile: (NSString *)name
{
NSString *fileName = [NSString stringWithFormat: @"%@%@",
NSString *fileName = [NSString stringWithFormat: @"%s%@",
ZONES_DIR, name];
return [NSBundle pathForGNUstepResource: fileName
ofType: @""
inDirectory: TIME_ZONE_DIR];