Artifact a3654b4d40735f31fac31e493a5585a7b46173867db0d12d32f1e1ea2d29344f:
- File
src/OFStdIOStream.m
— part of check-in
[62e2de30b9]
at
2015-02-16 08:39:17
on branch trunk
— Explicitly pass errno to exceptions
The old behaviour where the exception would access errno directly on
creation of the exception was very fragile. The two main problems with
it were that sometimes it would pick up an errno even though none had
been set and in other cases that when the exception was created errno
had already been overridden.This also greatly increases errno handling on Win32, especially in
conjunction with sockets. It can still be improved further, though. (user: js, size: 4023) [annotate] [blame] [check-ins using]
/* * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 * Jonathan Schleifer <js@webkeks.org> * * 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.QPL included in * the packaging of this file. * * Alternatively, it may be distributed under the terms of the GNU General * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ #include "config.h" /* Work around __block being used by glibc */ #include <stdlib.h> /* include any libc header to get the libc defines */ #ifdef __GLIBC__ # undef __USE_XOPEN #endif #include <errno.h> #include <unistd.h> #import "OFStdIOStream.h" #import "OFDate.h" #import "OFApplication.h" #import "OFOutOfRangeException.h" #import "OFReadFailedException.h" #import "OFWriteFailedException.h" OFStdIOStream *of_stdin = nil; OFStdIOStream *of_stdout = nil; OFStdIOStream *of_stderr = nil; @interface OFStdIOStream (OF_PRIVATE_CATEGORY) - (instancetype)OF_initWithFileDescriptor: (int)fd; @end void of_log(OFConstantString *format, ...) { void *pool = objc_autoreleasePoolPush(); OFDate *date; OFString *dateString, *me, *msg; va_list arguments; date = [OFDate date]; dateString = [date localDateStringWithFormat: @"%Y-%m-%d %H:%M:%S"]; me = [[OFApplication programName] lastPathComponent]; va_start(arguments, format); msg = [[[OFString alloc] initWithFormat: format arguments: arguments] autorelease]; va_end(arguments); [of_stderr writeFormat: @"[%@.%03d %@(%d)] %@\n", dateString, [date microsecond] / 1000, me, getpid(), msg]; objc_autoreleasePoolPop(pool); } @implementation OFStdIOStream + (void)load { of_stdin = [[OFStdIOStream alloc] OF_initWithFileDescriptor: 0]; of_stdout = [[OFStdIOStream alloc] OF_initWithFileDescriptor: 1]; of_stderr = [[OFStdIOStream alloc] OF_initWithFileDescriptor: 2]; } - init { OF_INVALID_INIT_METHOD } - (instancetype)OF_initWithFileDescriptor: (int)fd { self = [super init]; _fd = fd; return self; } - (bool)lowlevelIsAtEndOfStream { if (_fd == -1) return true; return _atEndOfStream; } - (size_t)lowlevelReadIntoBuffer: (void*)buffer length: (size_t)length { ssize_t ret; if (_fd == -1 || _atEndOfStream) @throw [OFReadFailedException exceptionWithObject: self requestedLength: length]; #ifndef _WIN32 if ((ret = read(_fd, buffer, length)) < 0) @throw [OFReadFailedException exceptionWithObject: self requestedLength: length errNo: errno]; #else if (length > UINT_MAX) @throw [OFOutOfRangeException exception]; if ((ret = read(_fd, buffer, (unsigned int)length)) < 0) @throw [OFReadFailedException exceptionWithObject: self requestedLength: length errNo: errno]; #endif if (ret == 0) _atEndOfStream = true; return ret; } - (void)lowlevelWriteBuffer: (const void*)buffer length: (size_t)length { if (_fd == -1 || _atEndOfStream) @throw [OFWriteFailedException exceptionWithObject: self requestedLength: length]; #ifndef _WIN32 if (write(_fd, buffer, length) < length) @throw [OFWriteFailedException exceptionWithObject: self requestedLength: length errNo: errno]; #else if (length > UINT_MAX) @throw [OFOutOfRangeException exception]; if (write(_fd, buffer, (unsigned int)length) < length) @throw [OFWriteFailedException exceptionWithObject: self requestedLength: length errNo: errno]; #endif } - (int)fileDescriptorForReading { return _fd; } - (int)fileDescriptorForWriting { return _fd; } - (void)close { if (_fd != -1) close(_fd); _fd = -1; } - autorelease { return self; } - retain { return self; } - (void)release { } - (unsigned int)retainCount { return OF_RETAIN_COUNT_MAX; } - (void)dealloc { OF_UNRECOGNIZED_SELECTOR /* Get rid of a stupid warning */ [super dealloc]; } @end