Index: .hgignore ================================================================== --- .hgignore +++ .hgignore @@ -18,13 +18,15 @@ config.status configure docs extra.mk generators/gen_tables +generators/gen_tables.exe generators/CaseFolding.txt generators/UnicodeData.txt objfw-config ObjFW.xcodeproj/*.mode1v3 ObjFW.xcodeproj/*.pbxuser src/objfw-defs.h src/ObjFW tests/tests +tests/tests.exe Index: configure.ac ================================================================== --- configure.ac +++ configure.ac @@ -339,10 +339,14 @@ ]) AC_MSG_RESULT($atomic_ops) AC_CHECK_LIB(socket, socket, LIBS="$LIBS -lsocket") AC_CHECK_LIB(ws2_32, main, LIBS="$LIBS -lws2_32") + +AC_CHECK_FUNC(gmtime_r, [ + AC_DEFINE(HAVE_GMTIME_R, 1, [Whether we have gmtime_r]) +]) AC_CHECK_HEADER(poll.h, [ AC_DEFINE(OF_HAVE_POLL, 1, [Whether poll is supported]) ]) AC_CHECK_HEADERS(sys/select.h, [ Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -9,10 +9,11 @@ OFArray.m \ OFAutoreleasePool.m \ OFBlock.m \ OFConstantString.m \ OFDataArray.m \ + OFDate.m \ OFDictionary.m \ OFExceptions.m \ OFFile.m \ OFHash.m \ OFEnumerator.m \ ADDED src/OFDate.h Index: src/OFDate.h ================================================================== --- src/OFDate.h +++ src/OFDate.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2008 - 2010 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE included in + * the packaging of this file. + */ + +#include + +#import "OFObject.h" + +#ifdef __MINGW32__ +/* + * They think they don't need suseconds_t and can use long instead in + * struct timeval... POSIX demands suseconds_t, of course. + */ +typedef long suseconds_t; +#endif + +/** + * \brief A class for storing, accessing and comparing dates. + */ +@interface OFDate: OFObject +{ + time_t sec; + suseconds_t usec; +} + +/** + * \return A new, autoreleased OFDate with the current date and time + */ ++ date; + +/** + * \param sec The seconds since 1970-01-01 00:00:00 + * \return A new, autoreleased OFDate with the specified date and time + */ ++ dateWithTimeIntervalSince1970: (time_t)sec; + +/** + * \param sec The seconds since 1970-01-01 00:00:00 + * \param usec The microsecond part of the time + * \return A new, autoreleased OFDate with the specified date and time + */ ++ dateWithTimeIntervalSince1970: (time_t)sec + microseconds: (suseconds_t)usec; + +/** + * Initializes an already allocated OFDate with the specified date and time. + * + * \param sec The seconds since 1970-01-01 00:00:00 + * \return An initialized OFDate with the specified date and time + */ +- initWithTimeIntervalSince1970: (time_t)sec; + +/** + * Initializes an already allocated OFDate with the specified date and time. + * + * \param sec The seconds since 1970-01-01 00:00:00 + * \param usec The microsecond part of the time + * \return An initialized OFDate with the specified date and time + */ +- initWithTimeIntervalSince1970: (time_t)sec + microseconds: (suseconds_t)usec; +@end ADDED src/OFDate.m Index: src/OFDate.m ================================================================== --- src/OFDate.m +++ src/OFDate.m @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2008 - 2010 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE included in + * the packaging of this file. + */ + +#include "config.h" + +#include + +#include + +#import "OFDate.h" +#import "OFString.h" +#import "OFExceptions.h" + +#if !defined(HAVE_GMTIME_R) && defined(OF_THREADS) +# import "OFThread.h" + +static OFMutex *mutex; +#endif + +@implementation OFDate +#if !defined(HAVE_GMTIME_R) && defined(OF_THREADS) ++ (void)initialize +{ + if (self == [OFDate class]) + mutex = [[OFMutex alloc] init]; +} +#endif + ++ date +{ + return [[[self alloc] init] autorelease]; +} + ++ dateWithTimeIntervalSince1970: (time_t)sec +{ + return [[[self alloc] initWithTimeIntervalSince1970: sec] autorelease]; +} + ++ dateWithTimeIntervalSince1970: (time_t)sec + microseconds: (suseconds_t)usec +{ + return [[[self alloc] initWithTimeIntervalSince1970: sec + microseconds: usec] autorelease]; +} + +- init +{ + struct timeval t; + + if (gettimeofday(&t, NULL)) { + Class c = isa; + [self release]; + @throw [OFInitializationFailedException newWithClass: c]; + } + + return [self initWithTimeIntervalSince1970: t.tv_sec + microseconds: t.tv_usec]; +} + +- initWithTimeIntervalSince1970: (time_t)sec_ +{ + return [self initWithTimeIntervalSince1970: sec_ + microseconds: 0]; +} + +- initWithTimeIntervalSince1970: (time_t)sec_ + microseconds: (suseconds_t)usec_ +{ + self = [super init]; + + sec = sec_; + usec = usec_; + + return self; +} + +- (BOOL)isEqual: (id)obj +{ + if (![obj isKindOfClass: [OFDate class]]) + return NO; + if (((OFDate*)obj)->sec != sec || ((OFDate*)obj)->usec != usec) + return NO; + + return YES; +} + +- copy +{ + return [self retain]; +} + +- (of_comparison_result_t)compare: (id)obj +{ + if (![obj isKindOfClass: [OFDate class]]) + @throw [OFInvalidArgumentException newWithClass: isa + selector: _cmd]; + + if (sec < ((OFDate*)obj)->sec) + return OF_ORDERED_ASCENDING; + if (sec > ((OFDate*)obj)->sec) + return OF_ORDERED_DESCENDING; + + if (usec < ((OFDate*)obj)->usec) + return OF_ORDERED_ASCENDING; + if (usec > ((OFDate*)obj)->usec) + return OF_ORDERED_DESCENDING; + + return OF_ORDERED_SAME; +} + +- (OFString*)description +{ + char str[20]; /* YYYY-MM-DD hh:mm:ss */ + +#ifdef HAVE_GMTIME_R + struct tm tm; + + if (gmtime_r(&sec, &tm) == NULL) + @throw [OFOutOfRangeException newWithClass: isa]; + + strftime(str, 20, "%Y-%m-%d %H:%M:%S", &tm); +#else + struct tm *tm; + +# ifdef OF_THREADS + [mutex lock]; + + @try { +# endif + if ((tm = gmtime(&sec)) == NULL) + @throw [OFOutOfRangeException newWithClass: isa]; + + strftime(str, 20, "%Y-%m-%d %H:%M:%S", tm); +# ifdef OF_THREADS + } @finally { + [mutex unlock]; + } +# endif +#endif + + if (usec == 0) + return [OFString stringWithFormat: @"%sZ", str]; + + return [OFString stringWithFormat: @"%s.%06dZ", str, usec]; +} +@end Index: src/ObjFW.h ================================================================== --- src/ObjFW.h +++ src/ObjFW.h @@ -25,10 +25,11 @@ #import "OFDictionary.h" #import "OFEnumerator.h" #import "OFNumber.h" +#import "OFDate.h" #import "OFStream.h" #import "OFStreamObserver.h" #import "OFFile.h" Index: tests/Makefile ================================================================== --- tests/Makefile +++ tests/Makefile @@ -4,10 +4,11 @@ PROG_NOINST = tests${PROG_SUFFIX} SRCS = OFArrayTests.m \ ${OFBLOCKTESTS_M} \ OFDataArrayTests.m \ + OFDateTests.m \ OFDictionaryTests.m \ OFFileTests.m \ OFListTests.m \ OFMD5HashTests.m \ OFNumberTests.m \ Index: tests/OFArrayTests.m ================================================================== --- tests/OFArrayTests.m +++ tests/OFArrayTests.m @@ -10,12 +10,12 @@ */ #include "config.h" #import "OFArray.h" -#import "OFAutoreleasePool.h" #import "OFString.h" +#import "OFAutoreleasePool.h" #import "OFExceptions.h" #import "TestsAppDelegate.h" static OFString *module = @"OFArray"; Index: tests/OFBlockTests.m ================================================================== --- tests/OFBlockTests.m +++ tests/OFBlockTests.m @@ -9,12 +9,12 @@ * the packaging of this file. */ #include "config.h" -#import "OFString.h" #import "OFBlock.h" +#import "OFString.h" #import "OFAutoreleasePool.h" #import "OFExceptions.h" #if defined(OF_OBJFW_RUNTIME) # include Index: tests/OFDataArrayTests.m ================================================================== --- tests/OFDataArrayTests.m +++ tests/OFDataArrayTests.m @@ -12,12 +12,12 @@ #include "config.h" #include #import "OFDataArray.h" -#import "OFAutoreleasePool.h" #import "OFString.h" +#import "OFAutoreleasePool.h" #import "OFExceptions.h" #import "TestsAppDelegate.h" static OFString *module; ADDED tests/OFDateTests.m Index: tests/OFDateTests.m ================================================================== --- tests/OFDateTests.m +++ tests/OFDateTests.m @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2008 - 2010 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE included in + * the packaging of this file. + */ + +#include "config.h" + +#import "OFDate.h" +#import "OFString.h" +#import "OFAutoreleasePool.h" + +#import "TestsAppDelegate.h" + +static OFString *module = @"OFDate"; + +@implementation TestsAppDelegate (OFDateTests) +- (void)dateTests +{ + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + OFDate *d1, *d2; + + TEST(@"+[dateWithTimeIntervalSince1970:]", + (d1 = [OFDate dateWithTimeIntervalSince1970: 0])) + + TEST(@"+[dateWithTimeIntervalSince1970:microseconds:", + (d2 = [OFDate dateWithTimeIntervalSince1970: 3600 * 25 + 5 + microseconds: 1])) + + TEST(@"-[description]", + [[d1 description] isEqual: @"1970-01-01 00:00:00Z"] && + [[d2 description] isEqual: @"1970-01-02 01:00:05.000001Z"]) + + TEST(@"-[isEqual:]", + [d1 isEqual: [OFDate dateWithTimeIntervalSince1970: 0]] && + ![d1 isEqual: [OFDate dateWithTimeIntervalSince1970: 0 + microseconds: 1]]) + + TEST(@"-[compare:]", [d1 compare: d2] == OF_ORDERED_ASCENDING) + + [pool drain]; +} +@end Index: tests/OFDictionaryTests.m ================================================================== --- tests/OFDictionaryTests.m +++ tests/OFDictionaryTests.m @@ -10,13 +10,13 @@ */ #include "config.h" #import "OFDictionary.h" +#import "OFString.h" #import "OFArray.h" #import "OFAutoreleasePool.h" -#import "OFString.h" #import "OFExceptions.h" #import "TestsAppDelegate.h" static OFString *module = @"OFDictionary"; Index: tests/OFFileTests.m ================================================================== --- tests/OFFileTests.m +++ tests/OFFileTests.m @@ -10,12 +10,12 @@ */ #include "config.h" #import "OFFile.h" -#import "OFAutoreleasePool.h" #import "OFString.h" +#import "OFAutoreleasePool.h" #import "OFArray.h" #import "OFExceptions.h" #import "TestsAppDelegate.h" Index: tests/OFListTests.m ================================================================== --- tests/OFListTests.m +++ tests/OFListTests.m @@ -10,12 +10,12 @@ */ #include "config.h" #import "OFList.h" -#import "OFAutoreleasePool.h" #import "OFString.h" +#import "OFAutoreleasePool.h" #import "OFExceptions.h" #import "TestsAppDelegate.h" static OFString *module = @"OFList"; Index: tests/OFMD5HashTests.m ================================================================== --- tests/OFMD5HashTests.m +++ tests/OFMD5HashTests.m @@ -12,13 +12,13 @@ #include "config.h" #include #import "OFMD5Hash.h" +#import "OFString.h" #import "OFFile.h" #import "OFAutoreleasePool.h" -#import "OFString.h" #import "OFExceptions.h" #import "TestsAppDelegate.h" static OFString *module = @"OFMD5Hash"; Index: tests/OFPluginTests.m ================================================================== --- tests/OFPluginTests.m +++ tests/OFPluginTests.m @@ -10,13 +10,12 @@ */ #include "config.h" #import "OFPlugin.h" -#import "OFAutoreleasePool.h" #import "OFString.h" -#import "OFExceptions.h" +#import "OFAutoreleasePool.h" #import "TestsAppDelegate.h" #import "plugin/TestPlugin.h" Index: tests/OFSHA1HashTests.m ================================================================== --- tests/OFSHA1HashTests.m +++ tests/OFSHA1HashTests.m @@ -12,13 +12,13 @@ #include "config.h" #include #import "OFSHA1Hash.h" +#import "OFString.h" #import "OFFile.h" #import "OFAutoreleasePool.h" -#import "OFString.h" #import "OFExceptions.h" #import "TestsAppDelegate.h" static OFString *module = @"OFHash"; Index: tests/OFStreamTests.m ================================================================== --- tests/OFStreamTests.m +++ tests/OFStreamTests.m @@ -11,12 +11,12 @@ #include "config.h" #include -#import "OFString.h" #import "OFStream.h" +#import "OFString.h" #import "OFAutoreleasePool.h" #import "TestsAppDelegate.h" static OFString *module = @"OFStream"; Index: tests/OFTCPSocketTests.m ================================================================== --- tests/OFTCPSocketTests.m +++ tests/OFTCPSocketTests.m @@ -14,12 +14,12 @@ #include #include #include #import "OFTCPSocket.h" -#import "OFAutoreleasePool.h" #import "OFString.h" +#import "OFAutoreleasePool.h" #import "OFExceptions.h" #import "macros.h" #import "TestsAppDelegate.h" Index: tests/OFThreadTests.m ================================================================== --- tests/OFThreadTests.m +++ tests/OFThreadTests.m @@ -10,12 +10,12 @@ */ #include "config.h" #import "OFThread.h" -#import "OFAutoreleasePool.h" #import "OFString.h" +#import "OFAutoreleasePool.h" #import "OFExceptions.h" #import "TestsAppDelegate.h" static OFString *module = @"OFThread"; Index: tests/OFXMLElementTests.m ================================================================== --- tests/OFXMLElementTests.m +++ tests/OFXMLElementTests.m @@ -13,11 +13,10 @@ #import "OFXMLElement.h" #import "OFString.h" #import "OFArray.h" #import "OFAutoreleasePool.h" -#import "OFString.h" #import "OFExceptions.h" #import "TestsAppDelegate.h" static OFString *module = @"OFXMLElement"; Index: tests/OFXMLParserTests.m ================================================================== --- tests/OFXMLParserTests.m +++ tests/OFXMLParserTests.m @@ -16,11 +16,10 @@ #import "OFXMLParser.h" #import "OFString.h" #import "OFArray.h" #import "OFAutoreleasePool.h" -#import "OFString.h" #import "OFExceptions.h" #import "TestsAppDelegate.h" static OFString *module = @"OFXMLParser"; Index: tests/TestsAppDelegate.h ================================================================== --- tests/TestsAppDelegate.h +++ tests/TestsAppDelegate.h @@ -77,10 +77,14 @@ @end @interface TestsAppDelegate (OFDataArrayTests) - (void)dataArrayTests; @end + +@interface TestsAppDelegate (OFDateTests) +- (void)dateTests; +@end @interface TestsAppDelegate (OFDictionaryTests) - (void)dictionaryTests; @end Index: tests/TestsAppDelegate.m ================================================================== --- tests/TestsAppDelegate.m +++ tests/TestsAppDelegate.m @@ -86,10 +86,11 @@ [self SHA1HashTests]; [self dataArrayTests]; [self arrayTests]; [self dictionaryTests]; [self listTests]; + [self dateTests]; [self numberTests]; [self streamTests]; [self TCPSocketTests]; #ifdef OF_THREADS [self threadTests];