/* Automatically generated from Squeak on #(21 October 2001 9:18:14 pm) */

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

/* Default EXPORT macro that does nothing (see comment in sq.h): */
#define EXPORT(returnType) returnType

/* Do not include the entire sq.h file but just those parts needed. */
/*  The virtual machine proxy definition */
#include "sqVirtualMachine.h"
/* Configuration options */
#include "sqConfig.h"
/* Platform specific definitions */
#include "sqPlatformSpecific.h"

#define true 1
#define false 0
#define null 0  /* using 'null' because nil is predefined in Think C */
#include "AsynchFilePlugin.h"

/* memory access macros */
#define byteAt(i) (*((unsigned char *) (i)))
#define byteAtput(i, val) (*((unsigned char *) (i)) = val)
#define longAt(i) (*((int *) (i)))
#define longAtput(i, val) (*((int *) (i)) = val)

/*** Variables ***/
static struct VirtualMachine* interpreterProxy;
static const char *moduleName = "AsynchFilePlugin 21 October 2001 (i)";

/*** Function Prototypes ***/
static AsyncFile * asyncFileValueOf(int oop);
#pragma export on
EXPORT(const char*) AsynchFilePlugin_getModuleName(void);
EXPORT(int) AsynchFilePlugin_initialiseModule(void);
EXPORT(int) AsynchFilePlugin_primitiveAsyncFileClose(void);
EXPORT(int) AsynchFilePlugin_primitiveAsyncFileOpen(void);
EXPORT(int) AsynchFilePlugin_primitiveAsyncFileReadResult(void);
EXPORT(int) AsynchFilePlugin_primitiveAsyncFileReadStart(void);
EXPORT(int) AsynchFilePlugin_primitiveAsyncFileWriteResult(void);
EXPORT(int) AsynchFilePlugin_primitiveAsyncFileWriteStart(void);
EXPORT(int) AsynchFilePlugin_setInterpreter(struct VirtualMachine* anInterpreter);
EXPORT(int) AsynchFilePlugin_shutdownModule(void);
#pragma export off


/*	Return a pointer to the first byte of the async file record within the given Smalltalk bytes object, or nil if oop is not an async file record. */

static AsyncFile * asyncFileValueOf(int oop) {
	interpreterProxy->success((!((oop & 1))) && ((interpreterProxy->isBytes(oop)) && ((interpreterProxy->slotSizeOf(oop)) == (sizeof(AsyncFile)))));
	if (interpreterProxy->failed()) {
		return null;
	}
	return (AsyncFile *) (oop + 4);
}


/*	Note: This is hardcoded so it can be run from Squeak.
	The module name is used for validating a module *after*
	it is loaded to check if it does really contain the module
	we're thinking it contains. This is important! */

EXPORT(const char*) AsynchFilePlugin_getModuleName(void) {
	return moduleName;
}


/*	Initialise the module */

EXPORT(int) AsynchFilePlugin_initialiseModule(void) {
	return asyncFileInit();
}

EXPORT(int) AsynchFilePlugin_primitiveAsyncFileClose(void) {
	AsyncFile *f;
	int fh;

	fh = interpreterProxy->stackValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	f = asyncFileValueOf(fh);
	asyncFileClose(f);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(1);
	return null;
}

EXPORT(int) AsynchFilePlugin_primitiveAsyncFileOpen(void) {
	int fileNameSize;
	int fOop;
	AsyncFile *f;
	char *fileName;
	int writeFlag;
	int semaIndex;

	interpreterProxy->success(interpreterProxy->isBytes(interpreterProxy->stackValue(2)));
	fileName = ((char *) (interpreterProxy->firstIndexableField(interpreterProxy->stackValue(2))));
	writeFlag = interpreterProxy->booleanValueOf(interpreterProxy->stackValue(1));
	semaIndex = interpreterProxy->stackIntegerValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	fileNameSize = interpreterProxy->slotSizeOf(((int) fileName) - 4);
	if (!(ioCanOpenAsyncFileOfSizeWritable(fileName, fileNameSize, writeFlag))) {
		interpreterProxy->primitiveFail();
		return null;
	}
	fOop = interpreterProxy->instantiateClassindexableSize(interpreterProxy->classByteArray(), sizeof(AsyncFile));
	f = asyncFileValueOf(fOop);
	if (!(interpreterProxy->failed())) {
		asyncFileOpen(f, (int)fileName, fileNameSize, writeFlag, semaIndex);
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(4, fOop);
	return null;
}

EXPORT(int) AsynchFilePlugin_primitiveAsyncFileReadResult(void) {
	AsyncFile *f;
	int count;
	int bufferPtr;
	int r;
	int bufferSize;
	int startIndex;
	int fhandle;
	int buffer;
	int start;
	int num;
	int _return_value;

	fhandle = interpreterProxy->stackValue(3);
	buffer = interpreterProxy->stackValue(2);
	start = interpreterProxy->stackIntegerValue(1);
	num = interpreterProxy->stackIntegerValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	f = asyncFileValueOf(fhandle);
	count = num;
	startIndex = start;

	/* in bytes or words */

	bufferSize = interpreterProxy->slotSizeOf(buffer);
	if (interpreterProxy->isWords(buffer)) {
		count = count * 4;
		startIndex = ((startIndex - 1) * 4) + 1;
		bufferSize = bufferSize * 4;
	}
	interpreterProxy->success((startIndex >= 1) && (((startIndex + count) - 1) <= bufferSize));

	/* adjust for zero-origin indexing */

	bufferPtr = ((((int) (interpreterProxy->firstIndexableField(buffer)))) + startIndex) - 1;
	if (!(interpreterProxy->failed())) {
		r = asyncFileReadResult(f, bufferPtr, count);
	}
	_return_value = interpreterProxy->integerObjectOf(r);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(5, _return_value);
	return null;
}

EXPORT(int) AsynchFilePlugin_primitiveAsyncFileReadStart(void) {
	AsyncFile *f;
	int fHandle;
	int fPosition;
	int count;

	fHandle = interpreterProxy->stackValue(2);
	fPosition = interpreterProxy->stackIntegerValue(1);
	count = interpreterProxy->stackIntegerValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	f = asyncFileValueOf(fHandle);
	asyncFileReadStart(f, fPosition, count);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(3);
	return null;
}

EXPORT(int) AsynchFilePlugin_primitiveAsyncFileWriteResult(void) {
	int r;
	AsyncFile *f;
	int fHandle;
	int _return_value;

	fHandle = interpreterProxy->stackValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	f = asyncFileValueOf(fHandle);
	r =  asyncFileWriteResult(f);
	_return_value = interpreterProxy->integerObjectOf(r);
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->popthenPush(2, _return_value);
	return null;
}

EXPORT(int) AsynchFilePlugin_primitiveAsyncFileWriteStart(void) {
	AsyncFile *f;
	int count;
	int bufferPtr;
	int bufferSize;
	int startIndex;
	int fHandle;
	int fPosition;
	int buffer;
	int start;
	int num;

	fHandle = interpreterProxy->stackValue(4);
	fPosition = interpreterProxy->stackIntegerValue(3);
	buffer = interpreterProxy->stackValue(2);
	start = interpreterProxy->stackIntegerValue(1);
	num = interpreterProxy->stackIntegerValue(0);
	if (interpreterProxy->failed()) {
		return null;
	}
	f = asyncFileValueOf(fHandle);
	if (interpreterProxy->failed()) {
		return null;
	}
	count = num;
	startIndex = start;

	/* in bytes or words */

	bufferSize = interpreterProxy->slotSizeOf(buffer);
	if (interpreterProxy->isWords(buffer)) {
		count = count * 4;
		startIndex = ((startIndex - 1) * 4) + 1;
		bufferSize = bufferSize * 4;
	}
	interpreterProxy->success((startIndex >= 1) && (((startIndex + count) - 1) <= bufferSize));

	/* adjust for zero-origin indexing */

	bufferPtr = ((((int) (interpreterProxy->firstIndexableField(buffer)))) + startIndex) - 1;
	if (!(interpreterProxy->failed())) {
		asyncFileWriteStart(f, fPosition, bufferPtr, count);
	}
	if (interpreterProxy->failed()) {
		return null;
	}
	interpreterProxy->pop(5);
	return null;
}


/*	Note: This is coded so that is can be run from Squeak. */

EXPORT(int) AsynchFilePlugin_setInterpreter(struct VirtualMachine* anInterpreter) {
	int ok;

	interpreterProxy = anInterpreter;
	ok = interpreterProxy->majorVersion() == VM_PROXY_MAJOR;
	if (ok == 0) {
		return 0;
	}
	ok = interpreterProxy->minorVersion() >= VM_PROXY_MINOR;
	return ok;
}


/*	Initialise the module */

EXPORT(int) AsynchFilePlugin_shutdownModule(void) {
	return asyncFileShutdown();
}
