//H+
//	Implementation of a simple object representing a memory-mapped file.
//H-

/* $Log:	MappedFile.m,v $
Revision 1.1  94/08/24  22:42:33  ediger
Initial revision

Revision 1.2  94/02/10  22:20:08  ediger
added - (char *)errorString method to assist in error handling

Revision 1.1  94/02/07  21:38:37  ediger
Initial revision
 */

#import <MappedFile.h>

@implementation MappedFile

static char MappedFileRcsIdent[] = "$Id: MappedFile.m,v 1.1 94/08/24 22:42:33 ediger Exp Locker: ediger $";

//F+  -init
//F-
- init
{
	[super init];

	mappedAddress = NULL;
	lastErrno = 0;
	lastKernReturn = KERN_SUCCESS;
	FileName = NULL;
	fd = -1;  // -1 signifies that file descriptor is not used.

	return self;
}

//F+  -free
//F-
- free
{
	if (fd > -1 || mappedAddress != NULL)
		[self unmap];

	if (FileName != NULL)
		free(FileName);

	[super free];

	return self;
}

//F+  -(BOOL)map
//
//	Returns TRUE if memory-mapping of file worked, FALSE if it failed.
//
//	Must set name of file to map first.
//F-
- (BOOL)map
{
	assert(FileName != NULL);

	if (fd > -1 || mappedAddress != NULL)
		[self unmap];

	fd = open(FileName, O_RDONLY);
	if (fd < 0)
	{
		lastErrno = errno;
		return FALSE;
	}

	if (fstat(fd, &statBuf) < 0)
	{
		lastErrno = errno;
		close(fd);
		return FALSE;
	}

	lastKernReturn = map_fd(fd, (vm_offset_t)NULL,
		(vm_offset_t *)&mappedAddress, TRUE, statBuf.st_size);

	if (lastKernReturn != KERN_SUCCESS)
	{
		close(fd);
		return FALSE;
	}

	return TRUE;
}

//F+  -(BOOL)unmap
//
//	Returns TRUE if unmapping of file worked, FALSE if it failed.
//
//F-
- (BOOL)unmap
{
	BOOL fSuccess;

	fSuccess = FALSE;

	if (mappedAddress == NULL || fd == -1)
		return TRUE;  // allow repeated use of this message

	lastKernReturn = vm_deallocate(task_self(), (vm_address_t)mappedAddress,
		statBuf.st_size);
	if (lastKernReturn == KERN_SUCCESS)
		fSuccess = TRUE;
	else
		mappedAddress = NULL;

	if (close(fd) < 0)
	{
		lastErrno = errno;
		fSuccess = FALSE;
	} else
		fd = -1;

	return fSuccess;
}

//F+	-(char *)address
//F-
- (char *)address
{
	return mappedAddress;
}

//F+	-(char *)filename
//F-
- (char *)filename
{
	return FileName;
}

//F+	-(int)size
//F-
- (int)size
{
	return statBuf.st_size;
}

//F+	-(int)lastUnixError
//F-
- (int)lastUnixError
{
	return lastErrno;
}

//F+	-(kern_return_t)lastMachError
//F-
- (kern_return_t)lastMachError
{
	return lastKernReturn;
}

//F+	-filename:(char *)fileName
//
//	Set filename of file to be memory mapped.
//	Possibly an unwise pseudo-method-name overloading.
//
//F-
- filename:(char *)fileName
{
	if (fileName != NULL && strlen(fileName) > 0)
	{
		if (FileName != NULL)
			free(FileName);

		FileName = malloc(strlen(fileName) + 1);

		if (FileName != NULL)
			strcpy(FileName, fileName);
	}

	return self;
}

//F+
//F-
- (char *)errorString
{
	char *bprErrorString = NULL;

	if (lastErrno != 0)
		bprErrorString = sys_errlist[lastErrno];
	else if (lastKernReturn != KERN_SUCCESS)
		bprErrorString = mach_error_string(lastKernReturn);
	else
		bprErrorString = "No error";

	return bprErrorString;
}

@end
