Index: src/OFDNSResolverSettings.m ================================================================== --- src/OFDNSResolverSettings.m +++ src/OFDNSResolverSettings.m @@ -46,19 +46,22 @@ /* Newer versions of libctru started using id as a parameter name. */ # define id id_3ds # include <3ds.h> # undef id #endif + +#ifdef OF_MORPHOS +# include +# include +# include +#endif #import "socket_helpers.h" #if defined(OF_HAIKU) # define HOSTS_PATH @"/system/settings/network/hosts" # define RESOLV_CONF_PATH @"/system/settings/network/resolv.conf" -#elif defined(OF_MORPHOS) -# define HOSTS_PATH @"ENV:sys/net/hosts" -# define RESOLV_CONF_PATH @"ENV:sys/net/resolv.conf" #elif defined(OF_AMIGAOS4) # define HOSTS_PATH @"DEVS:Internet/hosts" #elif defined(OF_AMIGAOS) # define HOSTS_PATH @"AmiTCP:db/hosts" # define RESOLV_CONF_PATH @"AmiTCP:db/resolv.conf" @@ -65,42 +68,118 @@ #else # define HOSTS_PATH @"/etc/hosts" # define RESOLV_CONF_PATH @"/etc/resolv.conf" #endif -#ifndef OF_WII static OFString * -domainFromHostname(void) +domainFromHostname(OFString *hostname) { - char hostname[256]; - OFString *domain, *ret; - - if (gethostname(hostname, 256) != 0) + if (hostname == nil) return nil; - domain = [OFString stringWithCString: hostname - encoding: [OFLocale encoding]]; - @try { - of_socket_address_parse_ip(domain, 0); + of_socket_address_parse_ip(hostname, 0); /* * If we are still here, the host name is a valid IP address. * We can't use that as local domain. */ return nil; } @catch (OFInvalidFormatException *e) { /* Not an IP address -> we can use it if it contains a dot. */ - size_t pos = [domain rangeOfString: @"."].location; + size_t pos = [hostname rangeOfString: @"."].location; if (pos == OF_NOT_FOUND) return nil; - ret = [domain substringFromIndex: pos + 1]; + return [hostname substringFromIndex: pos + 1]; + } +} + +#if !defined(OF_WII) && !defined(OF_MORPHOS) +static OFString * +obtainHostname(void) +{ + char hostname[256]; + + if (gethostname(hostname, 256) != 0) + return nil; + + return [OFString stringWithCString: hostname + encoding: [OFLocale encoding]]; +} +#endif + +#ifdef OF_MORPHOS +static OFString * +arexxCommand(const char *port, const char *command) +{ + struct Library *RexxSysBase; + struct MsgPort *replyPort = NULL; + struct RexxMsg *msg = NULL; + + if ((RexxSysBase = OpenLibrary("rexxsyslib.library", 36)) == NULL) + return nil; + + @try { + struct MsgPort *rexxPort; + + if ((replyPort = CreateMsgPort()) == NULL) + return nil; + + if ((msg = CreateRexxMsg(replyPort, NULL, port)) == NULL) + return nil; + + msg->rm_Action = RXCOMM | RXFF_RESULT; + + if ((msg->rm_Args[0] = (char *)CreateArgstring( + command, strlen(command))) == NULL) + return nil; + + Forbid(); + + if ((rexxPort = FindPort(port)) == NULL) { + Permit(); + return nil; + } + + PutMsg(rexxPort, &msg->rm_Node); + Permit(); + WaitPort(replyPort); + GetMsg(replyPort); + + if (msg->rm_Result1 != RC_OK || msg->rm_Result2 == 0) + return nil; + + return [OFString stringWithCString: (char *)msg->rm_Result2 + encoding: [OFLocale encoding]]; + } @finally { + if (msg != NULL) { + if (msg->rm_Args[0] != NULL) + DeleteArgstring(msg->rm_Args[0]); + if (msg->rm_Result2 != 0) + DeleteArgstring((char *)msg->rm_Result2); + + DeleteRexxMsg(msg); + } + + if (replyPort != NULL) + DeleteMsgPort(replyPort); + + CloseLibrary(RexxSysBase); } +} - return ret; +static OFArray OF_GENERIC(OFString *) * +parseNetStackArray(OFString *string) +{ + if (![string hasPrefix: @"["] || ![string hasSuffix: @"]"]) + return nil; + + string = [string substringWithRange: of_range(1, string.length - 2)]; + + return [string componentsSeparatedByString: @"|"]; } #endif @implementation OFDNSResolverSettings - (void)dealloc @@ -161,21 +240,19 @@ #else _configReloadInterval = 0; #endif } -#if defined(OF_HAVE_FILES) && !defined(OF_NINTENDO_3DS) +#if defined(OF_HAVE_FILES) && !defined(OF_MORPHOS) && !defined(OF_NINTENDO_3DS) - (void)parseHosts: (OFString *)path { void *pool = objc_autoreleasePoolPush(); OFCharacterSet *whitespaceCharacterSet = [OFCharacterSet whitespaceCharacterSet]; OFMutableDictionary *staticHosts; OFFile *file; OFString *line; - OFEnumerator *enumerator; - OFMutableArray *addresses; @try { file = [OFFile fileWithPath: path mode: @"r"]; } @catch (OFOpenItemFailedException *e) { @@ -184,11 +261,10 @@ } staticHosts = [OFMutableDictionary dictionary]; while ((line = [file readLine]) != nil) { - void *pool2 = objc_autoreleasePoolPush(); OFArray *components, *hosts; size_t pos; OFString *address; pos = [line rangeOfString: @"#"].location; @@ -197,41 +273,34 @@ components = [line componentsSeparatedByCharactersInSet: whitespaceCharacterSet options: OF_STRING_SKIP_EMPTY]; - if (components.count < 2) { - objc_autoreleasePoolPop(pool2); + if (components.count < 2) continue; - } address = components.firstObject; hosts = [components objectsInRange: of_range(1, components.count - 1)]; for (OFString *host in hosts) { - addresses = [staticHosts objectForKey: host]; + OFMutableArray *addresses = + [staticHosts objectForKey: host]; if (addresses == nil) { addresses = [OFMutableArray array]; [staticHosts setObject: addresses forKey: host]; } [addresses addObject: address]; } - - objc_autoreleasePoolPop(pool2); } - - enumerator = [staticHosts objectEnumerator]; - while ((addresses = [enumerator nextObject]) != nil) + for (OFMutableArray *addresses in [staticHosts objectEnumerator]) [addresses makeImmutable]; [staticHosts makeImmutable]; - - [_staticHosts release]; _staticHosts = [staticHosts copy]; objc_autoreleasePoolPop(pool); } @@ -386,10 +455,61 @@ _localDomain = [[OFString alloc] initWithCString: fixedInfo->DomainName encoding: encoding]; } #endif + +#ifdef OF_MORPHOS +- (void)obtainMorphOSSystemConfig +{ + void *pool = objc_autoreleasePoolPush(); + OFMutableDictionary *staticHosts; + + _nameServers = [parseNetStackArray(arexxCommand("NETSTACK", + "QUERY NAMESERVERS")) copy]; + _localDomain = [domainFromHostname(arexxCommand("NETSTACK", + "QUERY HOSTNAME")) copy]; + _searchDomains = [parseNetStackArray(arexxCommand("NETSTACK", + "QUERY DOMAINS")) copy]; + + staticHosts = [OFMutableDictionary dictionary]; + + for (OFString *entry in parseNetStackArray(arexxCommand("NETSTACK", + "QUERY HOSTS"))) { + OFArray *components = [entry componentsSeparatedByString: @" "]; + OFString *address; + OFArray *hosts; + + if (components.count < 2) + continue; + + address = components.firstObject; + hosts = [components objectsInRange: + of_range(1, components.count - 1)]; + + for (OFString *host in hosts) { + OFMutableArray *addresses = + [staticHosts objectForKey: host]; + + if (addresses == nil) { + addresses = [OFMutableArray array]; + [staticHosts setObject: addresses + forKey: host]; + } + + [addresses addObject: address]; + } + } + for (OFMutableArray *addresses in [staticHosts objectEnumerator]) + [addresses makeImmutable]; + + [staticHosts makeImmutable]; + _staticHosts = [staticHosts copy]; + + objc_autoreleasePoolPop(pool); +} +#endif #ifdef OF_AMIGAOS4 - (void)obtainAmigaOS4SystemConfig { OFMutableArray *nameServers = [OFMutableArray array]; @@ -508,10 +628,12 @@ if (path != nil) [self parseHosts: path]; # endif [self obtainWindowsSystemConfig]; +#elif defined(OF_MORPHOS) + [self obtainMorphOSSystemConfig]; #elif defined(OF_AMIGAOS4) [self parseHosts: HOSTS_PATH]; [self obtainAmigaOS4SystemConfig]; #elif defined(OF_NINTENDO_3DS) [self obtainNintendo3DSSytemConfig]; @@ -539,13 +661,13 @@ initWithObjects: @"127.0.0.1", @"::1", nil]; #else _nameServers = [[OFArray alloc] initWithObject: @"127.0.0.1"]; #endif -#ifndef OF_WII +#if !defined(OF_WII) && !defined(OF_MORPHOS) if (_localDomain == nil) - _localDomain = [domainFromHostname() copy]; + _localDomain = [domainFromHostname(obtainHostname()) copy]; #endif if (_searchDomains == nil) { if (_localDomain != nil) _searchDomains = [[OFArray alloc] Index: src/OFDate.m ================================================================== --- src/OFDate.m +++ src/OFDate.m @@ -108,10 +108,16 @@ } #if (!defined(HAVE_GMTIME_R) || !defined(HAVE_LOCALTIME_R)) && \ defined(OF_HAVE_THREADS) static OFMutex *mutex; + +static void +releaseMutex(void) +{ + [mutex release]; +} #endif #ifdef OF_WINDOWS static __time64_t (*func__mktime64)(struct tm *); #endif @@ -344,10 +350,11 @@ placeholder.isa = [OFDatePlaceholder class]; #if (!defined(HAVE_GMTIME_R) || !defined(HAVE_LOCALTIME_R)) && \ defined(OF_HAVE_THREADS) mutex = [[OFMutex alloc] init]; + atexit(releaseMutex); #endif #ifdef OF_WINDOWS if ((module = LoadLibrary("msvcrt.dll")) != NULL) func__mktime64 = (__time64_t (*)(struct tm *)) Index: src/OFFileURLHandler.m ================================================================== --- src/OFFileURLHandler.m +++ src/OFFileURLHandler.m @@ -83,11 +83,11 @@ # ifdef OF_AMIGAOS4 # define DeleteFile(path) Delete(path) # endif #endif -#if defined(OF_WINDOWS) || (defined(OF_AMIGAOS) && !defined(OF_MORPHOS)) +#if defined(OF_WINDOWS) || defined(OF_AMIGAOS) typedef struct { of_offset_t st_size; unsigned int st_mode; of_time_interval_t st_atime, st_mtime, st_ctime; # ifdef OF_WINDOWS @@ -107,13 +107,25 @@ # define S_ISLNK(mode) (mode & S_IFLNK) #endif #if defined(OF_FILE_MANAGER_SUPPORTS_OWNER) && defined(OF_HAVE_THREADS) static OFMutex *passwdMutex; + +static void +releasePasswdMutex(void) +{ + [passwdMutex release]; +} #endif #if !defined(HAVE_READDIR_R) && defined(OF_HAVE_THREADS) && !defined(OF_WINDOWS) static OFMutex *readdirMutex; + +static void +releaseReaddirMutex(void) +{ + [readdirMutex release]; +} #endif #ifdef OF_WINDOWS static int (*func__wutime64)(const wchar_t *, struct __utimbuf64 *); static WINAPI BOOLEAN (*func_CreateSymbolicLinkW)(LPCWSTR, LPCWSTR, DWORD); @@ -127,74 +139,60 @@ { return (double)((int64_t)filetime->dwHighDateTime << 32 | filetime->dwLowDateTime) / 10000000.0 - 11644473600.0; } -static void -setErrno(void) +static int +retrieveError(void) { switch (GetLastError()) { case ERROR_FILE_NOT_FOUND: case ERROR_PATH_NOT_FOUND: case ERROR_NO_MORE_FILES: - errno = ENOENT; - return; + return ENOENT; case ERROR_ACCESS_DENIED: - errno = EACCES; - return; + return EACCES; case ERROR_DIRECTORY: - errno = ENOTDIR; - return; + return ENOTDIR; case ERROR_NOT_READY: - errno = EBUSY; - return; + return EBUSY; + default: + return EIO; } - - errno = 0; } #endif #ifdef OF_AMIGAOS -static void -setErrno(void) +static int +retrieveError(void) { switch (IoErr()) { case ERROR_DELETE_PROTECTED: case ERROR_READ_PROTECTED: case ERROR_WRITE_PROTECTED: - errno = EACCES; - break; + return EACCES; case ERROR_DISK_NOT_VALIDATED: case ERROR_OBJECT_IN_USE: - errno = EBUSY; - break; + return EBUSY; case ERROR_OBJECT_EXISTS: - errno = EEXIST; - break; + return EEXIST; case ERROR_DIR_NOT_FOUND: case ERROR_NO_MORE_ENTRIES: case ERROR_OBJECT_NOT_FOUND: - errno = ENOENT; - break; + return ENOENT; case ERROR_NO_FREE_STORE: - errno = ENOMEM; - break; + return ENOMEM; case ERROR_DISK_FULL: - errno = ENOSPC; - break; + return ENOSPC; case ERROR_DIRECTORY_NOT_EMPTY: - errno = ENOTEMPTY; - break; + return ENOTEMPTY; case ERROR_DISK_WRITE_PROTECTED: - errno = EROFS; - break; + return EROFS; case ERROR_RENAME_ACROSS_DEVICES: - errno = EXDEV; - break; + return EXDEV; default: - errno = 0; - break; + return EIO; } } #endif static int @@ -210,14 +208,12 @@ else success = GetFileAttributesExA( [path cStringWithEncoding: [OFLocale encoding]], GetFileExInfoStandard, &data); - if (!success) { - setErrno(); - return -1; - } + if (!success) + return retrieveError(); buffer->st_size = (uint64_t)data.nFileSizeHigh << 32 | data.nFileSizeLow; if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) @@ -229,22 +225,18 @@ */ WIN32_FIND_DATAW findData; HANDLE findHandle; if ((findHandle = FindFirstFileW(path.UTF16String, - &findData)) == INVALID_HANDLE_VALUE) { - setErrno(); - return -1; - } + &findData)) == INVALID_HANDLE_VALUE) + return retrieveError(); @try { if (!(findData.dwFileAttributes & - FILE_ATTRIBUTE_REPARSE_POINT)) { + FILE_ATTRIBUTE_REPARSE_POINT)) /* Race? Indicate to try again. */ - errno = EAGAIN; - return -1; - } + return EAGAIN; buffer->st_mode = (findData.dwReserved0 == IO_REPARSE_TAG_SYMLINK ? S_IFLNK : S_IFREG); } @finally { @@ -261,11 +253,11 @@ buffer->st_ctime = buffer->st_birthtime = filetimeToTimeInterval(&data.ftCreationTime); buffer->fileAttributes = data.dwFileAttributes; return 0; -#elif defined(OF_AMIGAOS) && !defined(OF_MORPHOS) +#elif defined(OF_AMIGAOS) BPTR lock; # ifdef OF_AMIGAOS4 struct ExamineData *ed; # else struct FileInfoBlock fib; @@ -273,33 +265,37 @@ of_time_interval_t timeInterval; struct Locale *locale; struct DateStamp *date; if ((lock = Lock([path cStringWithEncoding: [OFLocale encoding]], - SHARED_LOCK)) == 0) { - setErrno(); - return -1; - } + SHARED_LOCK)) == 0) + return retrieveError(); -# ifdef OF_AMIGAOS4 +# if defined(OF_MORPHOS) + if (!Examine64(lock, &fib, TAG_DONE)) { +# elif defined(OF_AMIGAOS4) if ((ed = ExamineObjectTags(EX_FileLockInput, lock, TAG_END)) == NULL) { # else if (!Examine(lock, &fib)) { # endif + int error = retrieveError(); UnLock(lock); - - errno = 0; - return -1; + return error; } UnLock(lock); -# ifdef OF_AMIGAOS4 +# if defined(OF_MORPHOS) + buffer->st_size = fib.fib_Size64; +# elif defined(OF_AMIGAOS4) buffer->st_size = ed->FileSize; - buffer->st_mode = (EXD_IS_DIRECTORY(ed) ? S_IFDIR : S_IFREG); # else buffer->st_size = fib.fib_Size; +# endif +# ifdef OF_AMIGAOS4 + buffer->st_mode = (EXD_IS_DIRECTORY(ed) ? S_IFDIR : S_IFREG); +# else buffer->st_mode = (fib.fib_DirEntryType > 0 ? S_IFDIR : S_IFREG); # endif timeInterval = 252460800; /* 1978-01-01 */ @@ -327,26 +323,38 @@ FreeDosObject(DOS_EXAMINEDATA, ed); # endif return 0; #elif defined(HAVE_STAT64) - return stat64([path cStringWithEncoding: [OFLocale encoding]], buffer); + if (stat64([path cStringWithEncoding: [OFLocale encoding]], + buffer) != 0) + return errno; + + return 0; #else - return stat([path cStringWithEncoding: [OFLocale encoding]], buffer); + if (stat([path cStringWithEncoding: [OFLocale encoding]], buffer) != 0) + return errno; + + return 0; #endif } static int of_lstat(OFString *path, of_stat_t *buffer) { #if defined(HAVE_LSTAT) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS) && \ !defined(OF_NINTENDO_3DS) && !defined(OF_WII) # ifdef HAVE_LSTAT64 - return lstat64([path cStringWithEncoding: [OFLocale encoding]], buffer); + if (lstat64([path cStringWithEncoding: [OFLocale encoding]], + buffer) != 0) + return errno; # else - return lstat([path cStringWithEncoding: [OFLocale encoding]], buffer); + if (lstat([path cStringWithEncoding: [OFLocale encoding]], buffer) != 0) + return errno; # endif + + return 0; #else return of_stat(path, buffer); #endif } @@ -487,11 +495,11 @@ if ((handle = CreateFileW(path.UTF16String, 0, (FILE_SHARE_READ | FILE_SHARE_WRITE), NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT, NULL)) == INVALID_HANDLE_VALUE) @throw [OFRetrieveItemAttributesFailedException exceptionWithURL: URL - errNo: 0]; + errNo: retrieveError()]; @try { union { char bytes[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; REPARSE_DATA_BUFFER data; @@ -503,16 +511,16 @@ if (!DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, buffer.bytes, MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &size, NULL)) @throw [OFRetrieveItemAttributesFailedException exceptionWithURL: URL - errNo: 0]; + errNo: retrieveError()]; if (buffer.data.ReparseTag != IO_REPARSE_TAG_SYMLINK) @throw [OFRetrieveItemAttributesFailedException exceptionWithURL: URL - errNo: 0]; + errNo: retrieveError()]; # define slrb buffer.data.SymbolicLinkReparseBuffer tmp = slrb.PathBuffer + (slrb.SubstituteNameOffset / sizeof(wchar_t)); @@ -544,13 +552,15 @@ if (self != [OFFileURLHandler class]) return; #if defined(OF_FILE_MANAGER_SUPPORTS_OWNER) && defined(OF_HAVE_THREADS) passwdMutex = [[OFMutex alloc] init]; + atexit(releasePasswdMutex); #endif #if !defined(HAVE_READDIR_R) && !defined(OF_WINDOWS) && defined(OF_HAVE_THREADS) readdirMutex = [[OFMutex alloc] init]; + atexit(releaseReaddirMutex); #endif #ifdef OF_WINDOWS if ((module = LoadLibrary("msvcrt.dll")) != NULL) func__wutime64 = (int (*)(const wchar_t *, @@ -576,11 +586,11 @@ + (bool)of_directoryExistsAtPath: (OFString *)path { of_stat_t s; - if (of_stat(path, &s) == -1) + if (of_stat(path, &s) != 0) return false; return S_ISDIR(s.st_mode); } @@ -600,10 +610,11 @@ - (of_file_attributes_t)attributesOfItemAtURL: (OFURL *)URL { of_mutable_file_attributes_t ret = [OFMutableDictionary dictionary]; void *pool = objc_autoreleasePoolPush(); OFString *path; + int error; of_stat_t s; if (URL == nil) @throw [OFInvalidArgumentException exception]; @@ -610,14 +621,14 @@ if (![[URL scheme] isEqual: _scheme]) @throw [OFInvalidArgumentException exception]; path = URL.fileSystemRepresentation; - if (of_lstat(path, &s) == -1) + if ((error = of_lstat(path, &s)) != 0) @throw [OFRetrieveItemAttributesFailedException exceptionWithURL: URL - errNo: errno]; + errNo: error]; if (s.st_size < 0) @throw [OFOutOfRangeException exception]; [ret setObject: [NSNumber numberWithUnsignedLongLong: s.st_size] @@ -718,23 +729,20 @@ date.ds_Minute = ((LONG)modificationTime % 86400) / 60; date.ds_Tick = fmod(modificationTime, 60) * TICKS_PER_SECOND; # ifdef OF_AMIGAOS4 if (!SetDate([path cStringWithEncoding: [OFLocale encoding]], - &date) != 0) { + &date) != 0) # else if (!SetFileDate([path cStringWithEncoding: [OFLocale encoding]], - &date) != 0) { + &date) != 0) # endif - setErrno(); - @throw [OFSetItemAttributesFailedException exceptionWithURL: URL attributes: attributes failedAttribute: attributeKey - errNo: errno]; - } + errNo: retrieveError()]; #else of_time_interval_t lastAccessTime = lastAccessDate.timeIntervalSince1970; of_time_interval_t modificationTime = modificationDate.timeIntervalSince1970; @@ -923,11 +931,11 @@ @throw [OFInvalidArgumentException exception]; if (![URL.scheme isEqual: _scheme]) @throw [OFInvalidArgumentException exception]; - if (of_stat(URL.fileSystemRepresentation, &s) == -1) { + if (of_stat(URL.fileSystemRepresentation, &s) != 0) { objc_autoreleasePoolPop(pool); return false; } ret = S_ISREG(s.st_mode); @@ -947,11 +955,11 @@ @throw [OFInvalidArgumentException exception]; if (![URL.scheme isEqual: _scheme]) @throw [OFInvalidArgumentException exception]; - if (of_stat(URL.fileSystemRepresentation, &s) == -1) { + if (of_stat(URL.fileSystemRepresentation, &s) != 0) { objc_autoreleasePoolPop(pool); return false; } ret = S_ISDIR(s.st_mode); @@ -989,17 +997,14 @@ errNo: errno]; #elif defined(OF_AMIGAOS) BPTR lock; if ((lock = CreateDir( - [path cStringWithEncoding: [OFLocale encoding]])) == 0) { - setErrno(); - + [path cStringWithEncoding: [OFLocale encoding]])) == 0) @throw [OFCreateDirectoryFailedException exceptionWithURL: URL - errNo: errno]; - } + errNo: retrieveError()]; UnLock(lock); #else if (mkdir([path cStringWithEncoding: [OFLocale encoding]], 0777) != 0) @throw [OFCreateDirectoryFailedException @@ -1031,21 +1036,15 @@ if ([OFSystemInfo isWindowsNT]) { WIN32_FIND_DATAW fd; if ((handle = FindFirstFileW(path.UTF16String, - &fd)) == INVALID_HANDLE_VALUE) { - int errNo = 0; - - if (GetLastError() == ERROR_FILE_NOT_FOUND) - errNo = ENOENT; - + &fd)) == INVALID_HANDLE_VALUE) @throw [OFOpenItemFailedException exceptionWithURL: URL mode: nil - errNo: errNo]; - } + errNo: retrieveError()]; @try { do { OFString *file; @@ -1064,31 +1063,25 @@ if (GetLastError() != ERROR_NO_MORE_FILES) @throw [OFReadFailedException exceptionWithObject: self requestedLength: 0 - errNo: EIO]; + errNo: retrieveError()]; } @finally { FindClose(handle); } } else { of_string_encoding_t encoding = [OFLocale encoding]; WIN32_FIND_DATA fd; if ((handle = FindFirstFileA( [path cStringWithEncoding: encoding], &fd)) == - INVALID_HANDLE_VALUE) { - int errNo = 0; - - if (GetLastError() == ERROR_FILE_NOT_FOUND) - errNo = ENOENT; - + INVALID_HANDLE_VALUE) @throw [OFOpenItemFailedException exceptionWithURL: URL mode: nil - errNo: errNo]; - } + errNo: retrieveError()]; @try { do { OFString *file; @@ -1108,27 +1101,25 @@ if (GetLastError() != ERROR_NO_MORE_FILES) @throw [OFReadFailedException exceptionWithObject: self requestedLength: 0 - errNo: EIO]; + errNo: retrieveError()]; } @finally { FindClose(handle); } } #elif defined(OF_AMIGAOS) of_string_encoding_t encoding = [OFLocale encoding]; BPTR lock; if ((lock = Lock([path cStringWithEncoding: encoding], - SHARED_LOCK)) == 0) { - setErrno(); - - @throw [OFOpenItemFailedException exceptionWithURL: URL - mode: nil - errNo: errno]; - } + SHARED_LOCK)) == 0) + @throw [OFOpenItemFailedException + exceptionWithURL: URL + mode: nil + errNo: retrieveError()]; @try { # ifdef OF_AMIGAOS4 struct ExamineData *ed; APTR context; @@ -1137,11 +1128,11 @@ EX_DoCurrentDir, TRUE, EX_DataFields, EXF_NAME, TAG_END)) == NULL) @throw [OFOpenItemFailedException exceptionWithURL: URL mode: nil - errNo: 0]; + errNo: retrieveError()]; @try { while ((ed = ExamineDir(context)) != NULL) { OFString *file = [[OFString alloc] initWithCString: ed->Name @@ -1161,11 +1152,11 @@ if (!Examine(lock, &fib)) @throw [OFOpenItemFailedException exceptionWithURL: URL mode: nil - errNo: 0]; + errNo: retrieveError()]; while (ExNext(lock, &fib)) { OFString *file = [[OFString alloc] initWithCString: fib.fib_FileName encoding: encoding]; @@ -1180,11 +1171,11 @@ if (IoErr() != ERROR_NO_MORE_ENTRIES) @throw [OFReadFailedException exceptionWithObject: self requestedLength: 0 - errNo: EIO]; + errNo: retrieveError()]; } @finally { UnLock(lock); } #else of_string_encoding_t encoding = [OFLocale encoding]; @@ -1263,10 +1254,11 @@ - (void)removeItemAtURL: (OFURL *)URL { void *pool = objc_autoreleasePoolPush(); OFString *path; + int error; of_stat_t s; if (URL == nil) @throw [OFInvalidArgumentException exception]; @@ -1273,13 +1265,13 @@ if (![URL.scheme isEqual: _scheme]) @throw [OFInvalidArgumentException exception]; path = URL.fileSystemRepresentation; - if (of_lstat(path, &s) != 0) + if ((error = of_lstat(path, &s)) != 0) @throw [OFRemoveItemFailedException exceptionWithURL: URL - errNo: errno]; + errNo: error]; if (S_ISDIR(s.st_mode)) { OFArray *contents; @try { @@ -1341,16 +1333,14 @@ errNo: errno]; #endif } #ifdef OF_AMIGAOS - if (!DeleteFile([path cStringWithEncoding: [OFLocale encoding]])) { - setErrno(); - - @throw [OFRemoveItemFailedException exceptionWithURL: URL - errNo: errno]; - } + if (!DeleteFile([path cStringWithEncoding: [OFLocale encoding]])) + @throw [OFRemoveItemFailedException + exceptionWithURL: URL + errNo: retrieveError()]; #endif objc_autoreleasePoolPop(pool); } @@ -1388,11 +1378,11 @@ if (!func_CreateHardLinkW(destinationPath.UTF16String, sourcePath.UTF16String, NULL)) @throw [OFLinkFailedException exceptionWithSourceURL: source destinationURL: destination - errNo: 0]; + errNo: retrieveError()]; # endif objc_autoreleasePoolPop(pool); } #endif @@ -1428,11 +1418,11 @@ if (!func_CreateSymbolicLinkW(path.UTF16String, target.UTF16String, 0)) @throw [OFCreateSymbolicLinkFailedException exceptionWithURL: URL target: target - errNo: 0]; + errNo: retrieveError()]; # endif objc_autoreleasePoolPop(pool); } #endif @@ -1458,18 +1448,15 @@ of_string_encoding_t encoding = [OFLocale encoding]; if (!Rename([source.fileSystemRepresentation cStringWithEncoding: encoding], [destination.fileSystemRepresentation - cStringWithEncoding: encoding])) { - setErrno(); - + cStringWithEncoding: encoding])) @throw [OFMoveItemFailedException exceptionWithSourceURL: source destinationURL: destination - errNo: errno]; - } + errNo: retrieveError()]; #else int status; # ifdef OF_WINDOWS if ([OFSystemInfo isWindowsNT]) Index: src/OFString.m ================================================================== --- src/OFString.m +++ src/OFString.m @@ -2242,18 +2242,25 @@ - (OFArray *)componentsSeparatedByString: (OFString *)delimiter options: (int)options { void *pool; - OFMutableArray *array = [OFMutableArray array]; + OFMutableArray *array; const of_unichar_t *characters, *delimiterCharacters; bool skipEmpty = (options & OF_STRING_SKIP_EMPTY); size_t length = self.length; size_t delimiterLength = delimiter.length; size_t last; OFString *component; + if (delimiter == nil) + @throw [OFInvalidArgumentException exception]; + + if (delimiter.length == 0) + return [OFArray arrayWithObject: self]; + + array = [OFMutableArray array]; pool = objc_autoreleasePoolPush(); characters = self.characters; delimiterCharacters = delimiter.characters; @@ -2344,25 +2351,68 @@ - (long long)longLongValueWithBase: (int)base { void *pool = objc_autoreleasePoolPush(); const char *UTF8String = self.UTF8String; - char *endPointer = NULL; - long long value; - - errno = 0; - value = strtoll(UTF8String, &endPointer, base); - - if ((value == LLONG_MIN || value == LLONG_MAX) && errno == ERANGE) - @throw [OFOutOfRangeException exception]; - - /* Check if there are any invalid chars left */ - if (endPointer != NULL) - for (; *endPointer != '\0'; endPointer++) - /* Use isspace since strtoll uses the same. */ - if (!isspace((unsigned char)*endPointer)) + bool negative = false; + long long value = 0; + + while (of_ascii_isspace(*UTF8String)) + UTF8String++; + + switch (*UTF8String) { + case '-': + negative = true; + case '+': + UTF8String++; + } + + if (UTF8String[0] == '0') { + if (UTF8String[1] == 'x') { + if (base == 0) + base = 16; + + if (base != 16 || UTF8String[2] == '\0') @throw [OFInvalidFormatException exception]; + + UTF8String += 2; + } else { + if (base == 0) + base = 8; + + UTF8String++; + } + } + + while (*UTF8String != '\0') { + unsigned char c = of_ascii_toupper(*UTF8String++); + + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'A' && c <= 'Z') + c -= ('A' - 10); + else if (of_ascii_isspace(c)) { + while (*UTF8String != '\0') + if (!of_ascii_isspace(*UTF8String++)) + @throw [OFInvalidFormatException + exception]; + + break; + } else + @throw [OFInvalidFormatException exception]; + + if (c >= base) + @throw [OFInvalidFormatException exception]; + + if (LLONG_MAX / base < value || LLONG_MAX - (value * base) < c) + @throw [OFOutOfRangeException exception]; + + value = (value * base) + c; + } + + if (negative) + value *= -1; objc_autoreleasePoolPop(pool); return value; } @@ -2374,32 +2424,65 @@ - (unsigned long long)unsignedLongLongValueWithBase: (int)base { void *pool = objc_autoreleasePoolPush(); const char *UTF8String = self.UTF8String; - char *endPointer = NULL; - unsigned long long value; - - /* Use isspace since strtoull uses the same. */ - while (isspace((unsigned char)*UTF8String)) - UTF8String++; - - if (*UTF8String == '-') - @throw [OFInvalidFormatException exception]; - - errno = 0; - value = strtoull(UTF8String, &endPointer, base); - - if (value == ULLONG_MAX && errno == ERANGE) - @throw [OFOutOfRangeException exception]; - - /* Check if there are any invalid chars left */ - if (endPointer != NULL) - for (; *endPointer != '\0'; endPointer++) - /* Use isspace since strtoull uses the same. */ - if (!isspace((unsigned char)*endPointer)) - @throw [OFInvalidFormatException exception]; + unsigned long long value = 0; + + while (of_ascii_isspace(*UTF8String)) + UTF8String++; + + switch (*UTF8String) { + case '-': + @throw [OFInvalidFormatException exception]; + case '+': + UTF8String++; + } + + if (UTF8String[0] == '0') { + if (UTF8String[1] == 'x') { + if (base == 0) + base = 16; + + if (base != 16 || UTF8String[2] == '\0') + @throw [OFInvalidFormatException exception]; + + UTF8String += 2; + } else { + if (base == 0) + base = 8; + + UTF8String++; + } + } + + while (*UTF8String != '\0') { + unsigned char c = of_ascii_toupper(*UTF8String++); + + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'A' && c <= 'Z') + c -= ('A' - 10); + else if (of_ascii_isspace(c)) { + while (*UTF8String != '\0') + if (!of_ascii_isspace(*UTF8String++)) + @throw [OFInvalidFormatException + exception]; + + break; + } else + @throw [OFInvalidFormatException exception]; + + if (c >= base) + @throw [OFInvalidFormatException exception]; + + if (ULLONG_MAX / base < value || + ULLONG_MAX - (value * base) < c) + @throw [OFOutOfRangeException exception]; + + value = (value * base) + c; + } objc_autoreleasePoolPop(pool); return value; } Index: src/OFURLHandler.m ================================================================== --- src/OFURLHandler.m +++ src/OFURLHandler.m @@ -34,10 +34,16 @@ #endif static OFMutableDictionary OF_GENERIC(OFString *, OFURLHandler *) *handlers; #ifdef OF_HAVE_THREADS static OFMutex *mutex; + +static void +releaseMutex(void) +{ + [mutex release]; +} #endif @implementation OFURLHandler @synthesize scheme = _scheme; @@ -47,10 +53,11 @@ return; handlers = [[OFMutableDictionary alloc] init]; #ifdef OF_HAVE_THREADS mutex = [[OFMutex alloc] init]; + atexit(releaseMutex); #endif #ifdef OF_HAVE_FILES [self registerClass: [OFFileURLHandler class] forScheme: @"file"]; Index: src/OFUTF8String.m ================================================================== --- src/OFUTF8String.m +++ src/OFUTF8String.m @@ -1111,18 +1111,26 @@ - (OFArray *)componentsSeparatedByString: (OFString *)delimiter options: (int)options { void *pool; OFMutableArray *array; - const char *cString = delimiter.UTF8String; - size_t cStringLength = delimiter.UTF8StringLength; + const char *cString; + size_t cStringLength; bool skipEmpty = (options & OF_STRING_SKIP_EMPTY); size_t last; OFString *component; + if (delimiter == nil) + @throw [OFInvalidArgumentException exception]; + + if (delimiter.length == 0) + return [OFArray arrayWithObject: self]; + array = [OFMutableArray array]; pool = objc_autoreleasePoolPush(); + cString = delimiter.UTF8String; + cStringLength = delimiter.UTF8StringLength; if (cStringLength > _s->cStringLength) { [array addObject: [[self copy] autorelease]]; objc_autoreleasePoolPop(pool); Index: src/exceptions/OFException.m ================================================================== --- src/exceptions/OFException.m +++ src/exceptions/OFException.m @@ -34,11 +34,11 @@ #import "OFInitializationFailedException.h" #import "OFLockFailedException.h" #import "OFUnlockFailedException.h" -#if !defined(HAVE_STRERROR_R) && defined(OF_HAVE_THREADS) +#ifdef OF_HAVE_THREADS # import "mutex.h" #endif #if defined(OF_WINDOWS) && defined(OF_HAVE_SOCKETS) # include @@ -73,12 +73,16 @@ #if !defined(HAVE_STRERROR_R) && defined(OF_HAVE_THREADS) static of_mutex_t mutex; OF_CONSTRUCTOR() { - if (of_mutex_new(&mutex) != 0) - @throw [OFInitializationFailedException exception]; + OF_ENSURE(of_mutex_new(&mutex) == 0); +} + +OF_DESTRUCTOR() +{ + of_mutex_free(&mutex); } #endif OFString * of_strerror(int errNo) Index: src/macros.h ================================================================== --- src/macros.h +++ src/macros.h @@ -148,10 +148,13 @@ # define OF_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) #else # define OF_GCC_VERSION 0 #endif +#define OF_STRINGIFY(s) OF_STRINGIFY2(s) +#define OF_STRINGIFY2(s) #s + #ifndef __has_feature # define __has_feature(x) 0 #endif #ifndef __has_attribute @@ -362,14 +365,16 @@ #define OF_RETAIN_COUNT_MAX UINT_MAX #define OF_NOT_FOUND SIZE_MAX #ifdef OBJC_COMPILING_RUNTIME -# define OF_ENSURE(cond) \ - do { \ - if OF_UNLIKELY (!(cond)) \ - OBJC_ERROR("Failed to ensure condition:\n" #cond); \ +# define OF_ENSURE(cond) \ + do { \ + if OF_UNLIKELY (!(cond)) \ + objc_error("ObjFWRT @ " __FILE__ ":" \ + OF_STRINGIFY(__LINE__), \ + "Failed to ensure condition:\n" #cond); \ } while(0) #else # define OF_ENSURE(cond) \ do { \ if OF_UNLIKELY (!(cond)) { \ Index: src/runtime/amiga-glue.m ================================================================== --- src/runtime/amiga-glue.m +++ src/runtime/amiga-glue.m @@ -40,18 +40,16 @@ " blr\n" ); #endif bool __saveds -glue_objc_init PPC_PARAMS(unsigned int version, struct objc_libc *libc, - FILE **sF) +glue_objc_init PPC_PARAMS(unsigned int version, struct objc_libc *libc) { M68K_ARG(unsigned int, version, d0) M68K_ARG(struct objc_libc *, libc, a0) - M68K_ARG(FILE **, sF, a1) - return objc_init(version, libc, sF); + return objc_init(version, libc); } void __saveds glue___objc_exec_class PPC_PARAMS(struct objc_module *module) { Index: src/runtime/amiga-library.h ================================================================== --- src/runtime/amiga-library.h +++ src/runtime/amiga-library.h @@ -66,7 +66,6 @@ # endif int (*_Nonnull atexit)(void (*_Nonnull)(void)); void (*_Nonnull exit)(int); }; -extern bool objc_init(unsigned int, struct objc_libc *_Nonnull, - FILE *_Nonnull *_Nonnull); +extern bool objc_init(unsigned int, struct objc_libc *_Nonnull); Index: src/runtime/amiga-library.m ================================================================== --- src/runtime/amiga-library.m +++ src/runtime/amiga-library.m @@ -164,11 +164,10 @@ #ifdef OF_MORPHOS const ULONG __abox__ = 1; #endif struct ExecBase *SysBase; struct objc_libc libc; -FILE **__sF; #if defined(OF_AMIGAOS_M68K) __asm__ ( ".text\n" ".globl ___restore_a4\n" @@ -414,11 +413,11 @@ { return NULL; } bool -objc_init(unsigned int version, struct objc_libc *libc_, FILE **sF) +objc_init(unsigned int version, struct objc_libc *libc_) { #ifdef OF_AMIGAOS_M68K OBJC_M68K_ARG(struct ObjFWRTBase *, base, a6) #else register struct ObjFWRTBase *r12 __asm__("r12"); @@ -434,11 +433,10 @@ if (base->initialized) return true; memcpy(&libc, libc_, sizeof(libc)); - __sF = sF; #ifdef OF_AMIGAOS_M68K if ((size_t)_EH_FRAME_BEGINS__ != (size_t)_EH_FRAME_OBJECTS__) return false; Index: src/runtime/amigaos3.sfd ================================================================== --- src/runtime/amigaos3.sfd +++ src/runtime/amigaos3.sfd @@ -2,11 +2,11 @@ ==basetype struct Library * ==libname objfwrt68k.library ==bias 30 ==public * The following function is only for the linklib. -bool glue_objc_init(unsigned int version, struct objc_libc *_Nonnull libc, FILE *_Nonnull *_Nonnull sF)(d0,a0,a1) +bool glue_objc_init(unsigned int version, struct objc_libc *libc)(d0,a0) void glue___objc_exec_class(struct objc_module *_Nonnull module)(a0) IMP _Nonnull glue_objc_msg_lookup(id _Nullable object, SEL _Nonnull selector)(a0,a1) IMP _Nonnull glue_objc_msg_lookup_stret(id _Nullable object, SEL _Nonnull selector)(a0,a1) IMP _Nonnull glue_objc_msg_lookup_super(struct objc_super *_Nonnull super, SEL _Nonnull selector)(a0,a1) IMP _Nonnull glue_objc_msg_lookup_super_stret(struct objc_super *_Nonnull super, SEL _Nonnull selector)(a0,a1) Index: src/runtime/class.m ================================================================== --- src/runtime/class.m +++ src/runtime/class.m @@ -341,10 +341,17 @@ return; if (class->superclass) initializeClass(class->superclass); + /* + * Avoid double-initialization: One of the superclasses' +[initialize] + * might have called this class and hence it already got initialized. + */ + if (class->info & OBJC_CLASS_INFO_INITIALIZED) + return; + class->info |= OBJC_CLASS_INFO_DTABLE; class->isa->info |= OBJC_CLASS_INFO_DTABLE; objc_update_dtable(class); objc_update_dtable(class->isa); Index: src/runtime/linklib/linklib.m ================================================================== --- src/runtime/linklib/linklib.m +++ src/runtime/linklib/linklib.m @@ -144,11 +144,11 @@ if ((ObjFWRTBase = OpenLibrary(OBJFWRT_AMIGA_LIB, OBJFWRT_LIB_MINOR)) == NULL) error("Failed to open " OBJFWRT_AMIGA_LIB " version %lu!", OBJFWRT_LIB_MINOR); - if (!glue_objc_init(1, &libc, __sF)) + if (!glue_objc_init(1, &libc)) error("Failed to initialize " OBJFWRT_AMIGA_LIB "!", 0); initialized = true; } Index: src/runtime/misc.m ================================================================== --- src/runtime/misc.m +++ src/runtime/misc.m @@ -21,10 +21,14 @@ #include #include #include "ObjFWRT.h" #include "private.h" + +#ifdef OF_WINDOWS +# include +#endif #ifdef OF_AMIGAOS # define USE_INLINE_STDARG # include # include @@ -51,33 +55,40 @@ { enumerationMutationHandler = handler; } void -objc_error(const char *file, unsigned int line, const char *format, ...) +objc_error(const char *title, const char *format, ...) { -#ifdef OF_AMIGAOS -# define BUF_LEN 256 - char title[BUF_LEN]; +#if defined(OF_WINDOWS) || defined(OF_AMIGAOS) +# define BUF_LEN 512 char message[BUF_LEN]; int status; va_list args; - struct Library *IntuitionBase; -# ifdef OF_AMIGAOS4 - struct IntuitionIFace *IIntuition; -# endif - struct EasyStruct easy; - - status = snprintf(title, BUF_LEN, "ObjFWRT @ %s:%u", file, line); - if (status <= 0 || status >= BUF_LEN) - title[0] = '\0'; va_start(args, format); status = vsnprintf(message, BUF_LEN, format, args); if (status <= 0 || status >= BUF_LEN) message[0] = '\0'; va_end(args); +# undef BUF_LEN +#endif + +#if defined(OF_WINDOWS) + fprintf(stderr, "[%s] %s\n", title, message); + fflush(stderr); + + MessageBoxA(NULL, message, title, + MB_OK | MB_SYSTEMMODAL | MB_ICONERROR); + + exit(EXIT_FAILURE); +#elif defined(OF_AMIGAOS) + struct Library *IntuitionBase; +# ifdef OF_AMIGAOS4 + struct IntuitionIFace *IIntuition; +# endif + struct EasyStruct easy; # ifndef OF_AMIGAOS4 kprintf("[%s] %s\n", title, message); # endif @@ -103,17 +114,16 @@ # endif CloseLibrary(IntuitionBase); exit(EXIT_FAILURE); -# undef BUF_LEN #else va_list args; va_start(args, format); - fprintf(stderr, "[ObjFWRT @ %s:%u] ", file, line); + fprintf(stderr, "[%s] ", title); vfprintf(stderr, format, args); fprintf(stderr, "\n"); fflush(stderr); va_end(args); Index: src/runtime/morphos-clib.h ================================================================== --- src/runtime/morphos-clib.h +++ src/runtime/morphos-clib.h @@ -1,7 +1,7 @@ /* The following function is only for the linklib. */ -bool glue_objc_init(unsigned int, struct objc_libc *, FILE **); +bool glue_objc_init(unsigned int, struct objc_libc *); void glue___objc_exec_class(struct objc_module *); IMP glue_objc_msg_lookup(id, SEL); IMP glue_objc_msg_lookup_stret(id, SEL); IMP glue_objc_msg_lookup_super(struct objc_super *, SEL); IMP glue_objc_msg_lookup_super_stret(struct objc_super *, SEL); Index: src/runtime/morphos.fd ================================================================== --- src/runtime/morphos.fd +++ src/runtime/morphos.fd @@ -1,10 +1,10 @@ ##base _ObjFWRTBase ##bias 30 ##public * The following function is only for the linklib. -glue_objc_init(version,libc,sF)(sysv,r12base) +glue_objc_init(version,libc)(sysv,r12base) glue___objc_exec_class(module)(sysv,r12base) glue_objc_msg_lookup(object,selector)(sysv,r12base) glue_objc_msg_lookup_stret(object,selector)(sysv,r12base) glue_objc_msg_lookup_super(super,selector)(sysv,r12base) glue_objc_msg_lookup_super_stret(super,selector)(sysv,r12base) Index: src/runtime/private.h ================================================================== --- src/runtime/private.h +++ src/runtime/private.h @@ -283,13 +283,15 @@ return dtable->buckets[i]->buckets[j]; #endif } -extern void OF_NO_RETURN_FUNC objc_error(const char *_Nonnull file, - unsigned int line, const char *_Nonnull format, ...); -#define OBJC_ERROR(...) objc_error(__FILE__, __LINE__, __VA_ARGS__) +extern void OF_NO_RETURN_FUNC objc_error(const char *_Nonnull title, + const char *_Nonnull format, ...); +#define OBJC_ERROR(...) \ + objc_error("ObjFWRT @ " __FILE__ ":" OF_STRINGIFY(__LINE__), \ + __VA_ARGS__) #if defined(OF_ELF) # if defined(OF_X86_64) || defined(OF_X86) || defined(OF_POWERPC) || \ defined(OF_ARM64) || defined(OF_ARM) || \ defined(OF_MIPS64_N64) || defined(OF_MIPS) || \ Index: src/socket.m ================================================================== --- src/socket.m +++ src/socket.m @@ -24,10 +24,13 @@ #include #import "OFArray.h" #import "OFCharacterSet.h" #import "OFLocale.h" +#ifdef OF_HAVE_THREADS +# import "OFMutex.h" +#endif #import "OFString.h" #import "OFException.h" /* For some E* -> WSAE* defines */ #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" @@ -36,15 +39,11 @@ #import "OFUnlockFailedException.h" #import "socket.h" #import "socket_helpers.h" #ifdef OF_HAVE_THREADS -# if !defined(OF_AMIGAOS) || defined(OF_MORPHOS) -# import "mutex.h" -# else -# import "tlskey.h" -# endif +# import "tlskey.h" #endif #import "once.h" #ifdef OF_AMIGAOS # include @@ -54,11 +53,17 @@ # include <3ds/types.h> # include <3ds/services/soc.h> #endif #if defined(OF_HAVE_THREADS) && (!defined(OF_AMIGAOS) || defined(OF_MORPHOS)) -static of_mutex_t mutex; +static OFMutex *mutex; + +static void +releaseMutex(void) +{ + [mutex release]; +} #endif #if !defined(OF_AMIGAOS) || defined(OF_MORPHOS) || !defined(OF_HAVE_THREADS) static bool initSuccessful = false; #endif @@ -123,12 +128,12 @@ atexit((void (*)(void))socExit); # endif # if defined(OF_HAVE_THREADS) && (!defined(OF_AMIGAOS) || defined(OF_MORPHOS)) - if (of_mutex_new(&mutex) != 0) - return; + mutex = [[OFMutex alloc] init]; + atexit(releaseMutex); # ifdef OF_WII if (of_spinlock_new(&spinlock) != 0) return; # endif @@ -135,22 +140,22 @@ # endif initSuccessful = true; } -# ifdef OF_AMIGAOS OF_DESTRUCTOR() { +# ifdef OF_AMIGAOS # ifdef OF_AMIGAOS4 if (ISocket != NULL) DropInterface((struct Interface *)ISocket); # endif if (SocketBase != NULL) CloseLibrary(SocketBase); -} # endif +} #endif bool of_socket_init(void) { @@ -327,20 +332,15 @@ socklen_t *restrict addrLen) { int ret; # if defined(OF_HAVE_THREADS) && (!defined(OF_AMIGAOS) || defined(OF_MORPHOS)) - if (of_mutex_lock(&mutex) != 0) - @throw [OFLockFailedException exception]; - + [mutex lock]; # endif - ret = getsockname(sock, addr, addrLen); - # if defined(OF_HAVE_THREADS) && (!defined(OF_AMIGAOS) || defined(OF_MORPHOS)) - if (of_mutex_unlock(&mutex) != 0) - @throw [OFUnlockFailedException exception]; + [mutex unlock]; # endif return ret; } #endif Index: tests/OFStringTests.m ================================================================== --- tests/OFStringTests.m +++ tests/OFStringTests.m @@ -603,11 +603,14 @@ [[a objectAtIndex: i++] isEqual: @"bar"] && [[a objectAtIndex: i++] isEqual: @""] && [[a objectAtIndex: i++] isEqual: @"baz"] && [[a objectAtIndex: i++] isEqual: @""] && [[a objectAtIndex: i++] isEqual: @""] && - a.count == i) + a.count == i && + (a = [C(@"foo") componentsSeparatedByString: @""]) && + [[a objectAtIndex: 0] isEqual: @"foo"] && + a.count == 1) i = 0; TEST(@"-[componentsSeparatedByString:options:]", (a = [C(@"fooXXbarXXXXbazXXXX") componentsSeparatedByString: @"XX"