/* ALF objects */


#include <stdio.h>
#ifndef NULL
# define NULL ((void*)0)
#endif

#include <errno.h>

#include "Python.h"
#include "../src/alf.h"

#ifdef DMALLOC
#include "dmalloc.h"
#endif

static char alf_doc[] = 
"The alf module provides the appearance of large files on systems that don't\n"
"support them.  Large files are simulated using a directory containing\n"
"individual files that represent the chunks of data in the file.  Holes are\n"
"represented implicitly.  The interface is as close to that of a regular\n"
"file as practical.";

static PyObject *ErrorObject;

typedef struct {
    PyObject_HEAD
    ALF *obj;			/* real ALF object */
} ALFObject;

staticforward PyTypeObject ALF_Type;

#define ALFObject_Check(v)	((v)->ob_type == &ALF_Type)

/* ALF methods */

static PyObject *
ALF_read(ALFObject *self, PyObject *args)
{
    size_t nbytes = 8192;
    void *buf;
    PyObject *rv;

    /* this needs to adapt to allow nbytes to be optional */
    if (!PyArg_ParseTuple(args, "|i:read", &nbytes))
	return NULL;

    if ((buf = malloc(nbytes)) == NULL)
	return PyErr_NoMemory();
    
    if (PySequence_Length(args) != 0) {
	/* user provided an arg - read only that many bytes */

	nbytes = alf_read(buf, 1, nbytes, self->obj);
	if (nbytes == 0 && alf_error(self->obj)) {
	    free(buf);
	    return PyErr_SetFromErrno(ErrorObject);
	}
	else {
	    rv = Py_BuildValue("s#", buf, nbytes);
	    free(buf);
	    return rv;
	}
    }
    else {
	/* read was called without an arg - read the remainder of the file */
	size_t ind = 0;
	size_t n = 0;

	while (1) {
	    n = alf_read(buf+ind, 1, nbytes, self->obj);
	    if (n == 0) {
		if (alf_error(self->obj)) {
		    free(buf);
		    return PyErr_SetFromErrno(ErrorObject);
		}
		rv = Py_BuildValue("s#", buf, ind);
		free(buf);
		return rv;
	    }
	    else {
		ind += n;
		nbytes *= 2;
		if ((buf = realloc(buf, nbytes)) == NULL)
		    return PyErr_NoMemory();
	    }
	}
    }
}

static PyObject *
ALF_readline(ALFObject *self, PyObject *args)
{
    char *buf;
    int bufsize;
    int index;
    PyObject *result = NULL;

    if (!PyArg_ParseTuple(args, ":readline"))
	return NULL;

    bufsize = 160;
    index = 0;
    buf = malloc(bufsize);
    while (alf_gets(&buf[index], bufsize-index-1, self->obj) != NULL) {
	index += strlen(&buf[index]);
	if (buf[index-1] == '\n') {
	    break;
	}
	/* must have filled up the buffer */
	bufsize *= 2;
	buf = realloc(buf, bufsize);
    }

    result = PyString_FromStringAndSize(buf, index);
    free(buf);
    return result;
}

static PyObject *
ALF_write(ALFObject *self, PyObject *args)
{
    size_t nbytes;
    char *buf;

    if (!PyArg_ParseTuple(args, "s#:write", &buf, &nbytes))
	return NULL;

    nbytes = alf_write(buf, 1, nbytes, self->obj);
    if (nbytes == -1)
	return PyErr_SetFromErrno(ErrorObject);
    return Py_BuildValue("i", nbytes);
}

static PyObject *
ALF_flush(ALFObject *self, PyObject *args)
{
    if (!PyArg_ParseTuple(args, ":flush"))
	return NULL;

    if (alf_flush(self->obj) == -1)
	return PyErr_SetFromErrno(ErrorObject);
    Py_INCREF(Py_None);
    return Py_None;
}

static PyObject *
ALF_close(ALFObject *self, PyObject *args)
{
    int rv;

    if (!PyArg_ParseTuple(args, ":close"))
	return NULL;

    rv = alf_close(self->obj);
    self->obj = NULL;
    if (rv == -1)
	return PyErr_SetFromErrno(ErrorObject);
    Py_INCREF(Py_None);
    return Py_None;
}

static PyObject *
ALF_seek(ALFObject *self, PyObject *args)
{
    long long offset;
    int whence;

    if (!PyArg_ParseTuple(args, "Li:seek", &offset, &whence))
	return NULL;

    if (alf_seek(self->obj, offset, whence) == -1)
	return PyErr_SetFromErrno(ErrorObject);
    Py_INCREF(Py_None);
    return Py_None;
}

static PyObject *
ALF_rewind(ALFObject *self, PyObject *args)
{
    if (!PyArg_ParseTuple(args, ":rewind"))
	return NULL;

    alf_rewind(self->obj);
    Py_INCREF(Py_None);
    return Py_None;
}

static PyObject *
ALF_tell(ALFObject *self, PyObject *args)
{
    if (!PyArg_ParseTuple(args, ":tell"))
	return NULL;

    return Py_BuildValue("L", alf_tell(self->obj));
}

static PyObject *
ALF_truncate(ALFObject *self, PyObject *args)
{
    long long nbytes;
    if (!PyArg_ParseTuple(args, "L:truncate", &nbytes))
	return NULL;
    if (alf_truncate(self->obj, nbytes) == -1)
	return PyErr_SetFromErrno(ErrorObject);
    Py_INCREF(Py_None);
    return Py_None;
}

static PyObject *
ALF_getalf(ALFObject *self, PyObject *args)
{
    return PyCObject_FromVoidPtr(self->obj, NULL);
}

static PyMethodDef ALF_methods[] = {
	{"read",	(PyCFunction)ALF_read,	METH_VARARGS,
	"read([nbytes]) -> string"},
	{"readline",	(PyCFunction)ALF_readline,	METH_VARARGS,
	"readline() -> string"},
	{"write",	(PyCFunction)ALF_write,	METH_VARARGS,
	 "write(nbytes) -> int"},
	{"flush",	(PyCFunction)ALF_flush,	METH_VARARGS,
	 "flush() -> None"},
	{"close",	(PyCFunction)ALF_close,	METH_VARARGS,
	"close() -> None"},
	{"seek",	(PyCFunction)ALF_seek,	METH_VARARGS,
	 "seek(offset, whence) -> None"},
	{"rewind",	(PyCFunction)ALF_rewind, METH_VARARGS,
	 "rewind() -> None"},
	{"tell",	(PyCFunction)ALF_tell,	METH_VARARGS,
	 "tell() -> int"},
	{"truncate",	(PyCFunction)ALF_truncate,	METH_VARARGS,
	 "truncate(n) -> None"},
	{"getalf",	(PyCFunction)ALF_getalf,	METH_NOARGS,
	 "getalf() -> Cpointer"},
	{NULL, NULL, 0, NULL}		/* sentinel */
};

static PyObject *
ALF_getattr(ALFObject *self, char *name)
{
    return Py_FindMethod(ALF_methods, (PyObject *)self, name);
}

static void
ALF_dealloc(ALFObject *self)
{
    if (self->obj != NULL)
	(void)alf_close(self->obj);
    PyObject_Del(self);
}

statichere PyTypeObject ALF_Type = {
	/* The ob_type field must be initialized in the module init function
	 * to be portable to Windows without using C++. */
	PyObject_HEAD_INIT(NULL)
	0,			/*ob_size*/
	"alf",			/*tp_name*/
	sizeof(ALFObject),	/*tp_basicsize*/
	0,			/*tp_itemsize*/
	(destructor)ALF_dealloc, /*tp_dealloc*/
	0,			/*tp_print*/
	(getattrfunc)ALF_getattr, /*tp_getattr*/
	0,			/*tp_setattr*/
	0,			/*tp_compare*/
	0,			/*tp_repr*/
	0,			/*tp_as_number*/
	0,			/*tp_as_sequence*/
	0,			/*tp_as_mapping*/
	0,			/*tp_hash*/
        0,                      /*tp_call*/
        0,                      /*tp_str*/
        0,                      /*tp_getattro*/
        0,                      /*tp_setattro*/
        0,                      /*tp_as_buffer*/
        Py_TPFLAGS_DEFAULT,     /*tp_flags*/
        0,                      /*tp_doc*/
        0,                      /*tp_traverse*/
        0,                      /*tp_clear*/
        0,                      /*tp_richcompare*/
        0,                      /*tp_weaklistoffset*/
        0,                      /*tp_iter*/
        0,                      /*tp_iternext*/
        0,			/*tp_methods*/
        0,                      /*tp_members*/
        0,                      /*tp_getset*/
        0,                      /*tp_base*/
        0,                      /*tp_dict*/
        0,                      /*tp_descr_get*/
        0,                      /*tp_descr_set*/
        0,                      /*tp_dictoffset*/
        0,                      /*tp_init*/
        0,                      /*tp_alloc*/
        0,                      /*tp_new*/
        0,                      /*tp_free*/
        0,                      /*tp_is_gc*/
};
/* --------------------------------------------------------------------- */

static PyObject *
alf_new(/*@unused@*/ PyObject *self, PyObject *args)
{
    ALFObject *rv;
    char *path;
    char *mode = "r";
    unsigned int use_large = 0;

    if (!PyArg_ParseTuple(args, "s|si:new", &path, &mode, &use_large))
	return NULL;
    rv = PyObject_New(ALFObject, &ALF_Type);
    if (rv == NULL)
	return NULL;
    errno = 0;
    rv->obj = alf_open(path, mode, use_large);
    if (rv->obj == NULL){
	PyObject_Del(rv);
	return PyErr_SetFromErrno(ErrorObject);
    }
#if 0
    fprintf(stderr, "self: %p\n", rv);
    fprintf(stderr, "self->obj: %p\n", rv->obj);
    fprintf(stderr, "rv->ob_type: %p\n", rv->ob_type);
#endif
    return (PyObject *)rv;
}

/* List of functions defined in the module */

static PyMethodDef alf_methods[] = {
	{"new",		alf_new,		METH_VARARGS,
	 "new(path[, mode]) -> ALF object"},
	{"open",	alf_new,		METH_VARARGS,
	 "open(path[, mode]) -> ALF object"},
	{NULL, NULL, 0, NULL}		/* sentinel */
};


/* Initialization function for the module (*must* be called initalf) */

DL_EXPORT(void)
initalf(void)
{
	PyObject *m, *d;

	/* Initialize the type of the new type object here; doing it here
	 * is required for portability to Windows without requiring C++. */
	ALF_Type.ob_type = &PyType_Type;

	/* Create the module and add the functions */
	m = Py_InitModule3("alf", alf_methods, alf_doc);

	/* Add some symbolic constants to the module */
	d = PyModule_GetDict(m);
	ErrorObject = PyErr_NewException("alf.error", NULL, NULL);
	PyDict_SetItemString(d, "error", ErrorObject);
}


/*
 * Local Variables: ***
 * c-basic-offset: 4 ***
 * End: ***
 */


syntax highlighted by Code2HTML, v. 0.9.1