ObjFW  Artifact [7f1468fef3]

Artifact 7f1468fef3ec7f7fde3b1857c2702339d34271cd9ebe56709dc548f50488dcf4:

  • File src/OFStdIOStream.m — part of check-in [fe2cbe0021] at 2018-04-22 16:13:04 on branch trunk — runtime: Define BOOL to be the same as bool

    As we define the ABI, we can just replace BOOL with bool everywhere,
    including in ObjFW itself. For the Apple platforms where BOOL and bool
    are different, this is not a problem as BOOL and bool are passed and
    returned the same way in the ABI.

    This still defines BOOL to bool for compatibility, except on AmigaOS and
    Wii, which both have its own BOOL type. (user: js, size: 6965) [annotate] [blame] [check-ins using]


/*
 * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017,
 *               2018
 *   Jonathan Schleifer <js@heap.zone>
 *
 * 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"

#include <errno.h>

#include "unistd_wrapper.h"

#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif
#ifdef HAVE_SYS_TTYCOM_H
# include <sys/ttycom.h>
#endif

#import "OFStdIOStream.h"
#import "OFStdIOStream+Private.h"
#import "OFDate.h"
#import "OFApplication.h"
#ifdef OF_WINDOWS
# include "OFStdIOStream_Win32Console.h"
#endif

#import "OFNotOpenException.h"
#import "OFOutOfRangeException.h"
#import "OFReadFailedException.h"
#import "OFWriteFailedException.h"

#ifdef OF_MORPHOS
# include <proto/exec.h>
#endif

/* References for static linking */
#ifdef OF_WINDOWS
void
_reference_to_OFStdIOStream_Win32Console(void)
{
	[OFStdIOStream_Win32Console class];
}
#endif

OFStdIOStream *of_stdin = nil;
OFStdIOStream *of_stdout = nil;
OFStdIOStream *of_stderr = nil;

#ifdef OF_MORPHOS
OF_DESTRUCTOR()
{
	[of_stdin dealloc];
	[of_stdout dealloc];
	[of_stderr dealloc];
}
#endif

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"];
#ifdef OF_HAVE_FILES
	me = [[OFApplication programName] lastPathComponent];
#else
	me = [OFApplication programName];
#endif

	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
#ifndef OF_WINDOWS
+ (void)load
{
# ifndef OF_MORPHOS
	of_stdin = [[OFStdIOStream alloc] of_initWithFileDescriptor: 0];
	of_stdout = [[OFStdIOStream alloc] of_initWithFileDescriptor: 1];
	of_stderr = [[OFStdIOStream alloc] of_initWithFileDescriptor: 2];
# else
	BPTR input = Input(), output = Output();
	BPTR error = ((struct Process *)FindTask(NULL))->pr_CES;
	bool inputClosable = false, outputClosable = false,
	    errorClosable = false;

	if (input == 0) {
		input = Open("*", MODE_OLDFILE);
		inputClosable = true;
	}

	if (output == 0) {
		output = Open("*", MODE_OLDFILE);
		outputClosable = true;
	}

	if (error == 0) {
		error = Open("*", MODE_OLDFILE);
		errorClosable = true;
	}

	of_stdin = [[OFStdIOStream alloc] of_initWithHandle: input
						   closable: inputClosable];
	of_stdout = [[OFStdIOStream alloc] of_initWithHandle: output
						    closable: outputClosable];
	of_stderr = [[OFStdIOStream alloc] of_initWithHandle: error
						    closable: errorClosable];
# endif
}
#endif

- (instancetype)init
{
	OF_INVALID_INIT_METHOD
}

#ifndef OF_MORPHOS
- (instancetype)of_initWithFileDescriptor: (int)fd
{
	self = [super init];

	_fd = fd;

	return self;
}
#else
- (instancetype)of_initWithHandle: (BPTR)handle
			 closable: (bool)closable
{
	self = [super init];

	_handle = handle;
	_closable = closable;

	return self;
}
#endif

- (void)dealloc
{
	[self close];

	[super dealloc];
}

- (bool)lowlevelIsAtEndOfStream
{
#ifndef OF_MORPHOS
	if (_fd == -1)
#else
	if (_handle == 0)
#endif
		@throw [OFNotOpenException exceptionWithObject: self];

	return _atEndOfStream;
}

- (size_t)lowlevelReadIntoBuffer: (void *)buffer
			  length: (size_t)length
{
	ssize_t ret;

#ifndef OF_MORPHOS
	if (_fd == -1)
		@throw [OFNotOpenException exceptionWithObject: self];

# ifndef OF_WINDOWS
	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
#else
	if (_handle == 0)
		@throw [OFNotOpenException exceptionWithObject: self];

	if (length > LONG_MAX)
		@throw [OFOutOfRangeException exception];

	if ((ret = Read(_handle, buffer, length)) < 0)
		@throw [OFReadFailedException exceptionWithObject: self
						  requestedLength: length
							    errNo: EIO];
#endif

	if (ret == 0)
		_atEndOfStream = true;

	return ret;
}

- (size_t)lowlevelWriteBuffer: (const void *)buffer
		       length: (size_t)length
{
#ifndef OF_MORPHOS
	if (_fd == -1)
		@throw [OFNotOpenException exceptionWithObject: self];

# ifndef OF_WINDOWS
	ssize_t bytesWritten;

	if (length > SSIZE_MAX)
		@throw [OFOutOfRangeException exception];

	if ((bytesWritten = write(_fd, buffer, length)) < 0)
		@throw [OFWriteFailedException exceptionWithObject: self
						   requestedLength: length
						      bytesWritten: 0
							     errNo: errno];
# else
	int bytesWritten;

	if (length > INT_MAX)
		@throw [OFOutOfRangeException exception];

	if ((bytesWritten = write(_fd, buffer, (int)length)) < 0)
		@throw [OFWriteFailedException exceptionWithObject: self
						   requestedLength: length
						      bytesWritten: 0
							     errNo: errno];
# endif
#else
	LONG bytesWritten;

	if (_handle == 0)
		@throw [OFNotOpenException exceptionWithObject: self];

	if (length > SSIZE_MAX)
		@throw [OFOutOfRangeException exception];

	if ((bytesWritten = Write(_handle, (void *)buffer, length)) < 0)
		@throw [OFWriteFailedException exceptionWithObject: self
						   requestedLength: length
						      bytesWritten: 0
							     errNo: EIO];
#endif

	return (size_t)bytesWritten;
}

#if !defined(OF_WINDOWS) && !defined(OF_MORPHOS)
- (int)fileDescriptorForReading
{
	return _fd;
}

- (int)fileDescriptorForWriting
{
	return _fd;
}
#endif

- (void)close
{
#ifndef OF_MORPHOS
	if (_fd != -1)
		close(_fd);

	_fd = -1;
#else
	if (_closable && _handle != 0)
		Close(_handle);

	_handle = 0;
#endif

	[super close];
}

- (instancetype)autorelease
{
	return self;
}

- (instancetype)retain
{
	return self;
}

- (void)release
{
}

- (unsigned int)retainCount
{
	return OF_RETAIN_COUNT_MAX;
}

- (int)columns
{
#if defined(HAVE_SYS_IOCTL_H) && defined(TIOCGWINSZ) && !defined(OF_MORPHOS)
	struct winsize ws;

	if (ioctl(_fd, TIOCGWINSZ, &ws) != 0)
		return -1;

	return ws.ws_col;
#else
	return -1;
#endif
}

- (int)rows
{
#if defined(HAVE_SYS_IOCTL_H) && defined(TIOCGWINSZ) && !defined(OF_MORPHOS)
	struct winsize ws;

	if (ioctl(_fd, TIOCGWINSZ, &ws) != 0)
		return -1;

	return ws.ws_row;
#else
	return -1;
#endif
}
@end