Index: src/OFFile.h ================================================================== --- src/OFFile.h +++ src/OFFile.h @@ -27,10 +27,11 @@ # undef BOOL # define OF_INVALID_FILE_HANDLE ((of_file_handle_t){ 0, false }) # define OF_FILE_HANDLE_IS_VALID(h) (h.handle != 0) typedef struct of_file_handle_t { BPTR handle; + size_t index; bool append; } of_file_handle_t; #endif OF_ASSUME_NONNULL_BEGIN Index: src/OFFile.m ================================================================== --- src/OFFile.m +++ src/OFFile.m @@ -14,10 +14,11 @@ * file. */ #include "config.h" +#include #include #ifdef HAVE_FCNTL_H # include #endif @@ -28,10 +29,11 @@ #endif #import "OFFile.h" #import "OFString.h" #import "OFLocalization.h" +#import "OFDataArray.h" #import "OFInitializationFailedException.h" #import "OFInvalidArgumentException.h" #import "OFOpenItemFailedException.h" #import "OFOutOfRangeException.h" @@ -64,10 +66,41 @@ # define O_EXCL 0 #endif #ifndef O_EXLOCK # define O_EXLOCK 0 #endif + +#if !defined(OF_MORPHOS) || defined(OF_IXEMUL) +# define closeHandle(h) close(h) +#else +static OFDataArray *openHandles = nil; + +static void +closeHandle(of_file_handle_t handle) +{ + if (handle.index != SIZE_MAX) { + BPTR *handles = [openHandles items]; + size_t count = [openHandles count]; + + assert(handles[handle.index] == handle.handle); + + handles[handle.index] = handles[count - 1]; + [openHandles removeItemAtIndex: count - 1]; + } + + Close(handle.handle); +} + +OF_DESTRUCTOR() +{ + BPTR *handles = [openHandles items]; + size_t count = [openHandles count]; + + for (size_t i = 0; i < count; i++) + Close(handles[i]); +} +#endif #if !defined(OF_MORPHOS) || defined(OF_IXEMUL) static int parseMode(const char *mode) { @@ -156,10 +189,14 @@ @implementation OFFile + (void)initialize { if (self != [OFFile class]) return; + +#if defined(OF_MORPHOS) && !defined(OF_IXEMUL) + openHandles = [[OFDataArray alloc] initWithItemSize: sizeof(BPTR)]; +#endif #ifdef OF_WII if (!fatInitDefault()) @throw [OFInitializationFailedException exceptionWithClass: self]; @@ -217,10 +254,12 @@ @throw [OFOpenItemFailedException exceptionWithPath: path mode: mode errNo: errno]; #else + handle.index = SIZE_MAX; + if ((flags = parseMode([mode UTF8String], &handle.append)) == -1) @throw [OFInvalidArgumentException exception]; if ((handle.handle = Open([path cStringWithEncoding: @@ -227,13 +266,16 @@ [OFLocalization encoding]], flags)) == 0) @throw [OFOpenItemFailedException exceptionWithPath: path mode: mode]; + [openHandles addItem: &handle.handle]; + handle.index = [openHandles count] - 1; + if (handle.append) { if (Seek64(handle.handle, 0, OFFSET_END) == -1) { - Close(handle.handle); + closeHandle(handle); @throw [OFOpenItemFailedException exceptionWithPath: path mode: mode]; } } @@ -246,15 +288,11 @@ } @try { self = [self initWithHandle: handle]; } @catch (id e) { -#if !defined(OF_MORPHOS) || defined(OF_IXEMUL) - close(handle); -#else - Close(handle.handle); -#endif + closeHandle(handle); @throw e; } return self; } @@ -417,15 +455,11 @@ #endif - (void)close { if (OF_FILE_HANDLE_IS_VALID(_handle)) -#if !defined(OF_MORPHOS) || defined(OF_IXEMUL) - close(_handle); -#else - Close(_handle.handle); -#endif + closeHandle(_handle); _handle = OF_INVALID_FILE_HANDLE; [super close]; }