symbian-qemu-0.9.1-12/python-2.6.1/Modules/cdmodule.c
changeset 1 2fb8b9db1c86
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/symbian-qemu-0.9.1-12/python-2.6.1/Modules/cdmodule.c	Fri Jul 31 15:01:17 2009 +0100
@@ -0,0 +1,800 @@
+/* CD module -- interface to Mark Callow's and Roger Chickering's */
+ /* CD Audio Library (CD). */
+
+#include <sys/types.h>
+#include <cdaudio.h>
+#include "Python.h"
+
+#define NCALLBACKS	8
+
+typedef struct {
+	PyObject_HEAD
+	CDPLAYER *ob_cdplayer;
+} cdplayerobject;
+
+static PyObject *CdError;		/* exception cd.error */
+
+static PyObject *
+CD_allowremoval(cdplayerobject *self, PyObject *args)
+{
+	if (!PyArg_ParseTuple(args, ":allowremoval"))
+		return NULL;
+
+	CDallowremoval(self->ob_cdplayer);
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *
+CD_preventremoval(cdplayerobject *self, PyObject *args)
+{
+	if (!PyArg_ParseTuple(args, ":preventremoval"))
+		return NULL;
+
+	CDpreventremoval(self->ob_cdplayer);
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *
+CD_bestreadsize(cdplayerobject *self, PyObject *args)
+{
+	if (!PyArg_ParseTuple(args, ":bestreadsize"))
+		return NULL;
+
+	return PyInt_FromLong((long) CDbestreadsize(self->ob_cdplayer));
+}
+
+static PyObject *
+CD_close(cdplayerobject *self, PyObject *args)
+{
+	if (!PyArg_ParseTuple(args, ":close"))
+		return NULL;
+
+	if (!CDclose(self->ob_cdplayer)) {
+		PyErr_SetFromErrno(CdError); /* XXX - ??? */
+		return NULL;
+	}
+	self->ob_cdplayer = NULL;
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *
+CD_eject(cdplayerobject *self, PyObject *args)
+{
+	CDSTATUS status;
+
+	if (!PyArg_ParseTuple(args, ":eject"))
+		return NULL;
+
+	if (!CDeject(self->ob_cdplayer)) {
+		if (CDgetstatus(self->ob_cdplayer, &status) &&
+		    status.state == CD_NODISC)
+			PyErr_SetString(CdError, "no disc in player");
+		else
+			PyErr_SetString(CdError, "eject failed");
+		return NULL;
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+	
+static PyObject *
+CD_getstatus(cdplayerobject *self, PyObject *args)
+{
+	CDSTATUS status;
+
+	if (!PyArg_ParseTuple(args, ":getstatus"))
+		return NULL;
+
+	if (!CDgetstatus(self->ob_cdplayer, &status)) {
+		PyErr_SetFromErrno(CdError); /* XXX - ??? */
+		return NULL;
+	}
+
+	return Py_BuildValue("(ii(iii)(iii)(iii)iiii)", status.state,
+		       status.track, status.min, status.sec, status.frame,
+		       status.abs_min, status.abs_sec, status.abs_frame,
+		       status.total_min, status.total_sec, status.total_frame,
+		       status.first, status.last, status.scsi_audio,
+		       status.cur_block);
+}
+	
+static PyObject *
+CD_gettrackinfo(cdplayerobject *self, PyObject *args)
+{
+	int track;
+	CDTRACKINFO info;
+	CDSTATUS status;
+
+	if (!PyArg_ParseTuple(args, "i:gettrackinfo", &track))
+		return NULL;
+
+	if (!CDgettrackinfo(self->ob_cdplayer, track, &info)) {
+		if (CDgetstatus(self->ob_cdplayer, &status) &&
+		    status.state == CD_NODISC)
+			PyErr_SetString(CdError, "no disc in player");
+		else
+			PyErr_SetString(CdError, "gettrackinfo failed");
+		return NULL;
+	}
+
+	return Py_BuildValue("((iii)(iii))",
+		       info.start_min, info.start_sec, info.start_frame,
+		       info.total_min, info.total_sec, info.total_frame);
+}
+	
+static PyObject *
+CD_msftoblock(cdplayerobject *self, PyObject *args)
+{
+	int min, sec, frame;
+
+	if (!PyArg_ParseTuple(args, "iii:msftoblock", &min, &sec, &frame))
+		return NULL;
+
+	return PyInt_FromLong((long) CDmsftoblock(self->ob_cdplayer,
+						min, sec, frame));
+}
+	
+static PyObject *
+CD_play(cdplayerobject *self, PyObject *args)
+{
+	int start, play;
+	CDSTATUS status;
+
+	if (!PyArg_ParseTuple(args, "ii:play", &start, &play))
+		return NULL;
+
+	if (!CDplay(self->ob_cdplayer, start, play)) {
+		if (CDgetstatus(self->ob_cdplayer, &status) &&
+		    status.state == CD_NODISC)
+			PyErr_SetString(CdError, "no disc in player");
+		else
+			PyErr_SetString(CdError, "play failed");
+		return NULL;
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+	
+static PyObject *
+CD_playabs(cdplayerobject *self, PyObject *args)
+{
+	int min, sec, frame, play;
+	CDSTATUS status;
+
+	if (!PyArg_ParseTuple(args, "iiii:playabs", &min, &sec, &frame, &play))
+		return NULL;
+
+	if (!CDplayabs(self->ob_cdplayer, min, sec, frame, play)) {
+		if (CDgetstatus(self->ob_cdplayer, &status) &&
+		    status.state == CD_NODISC)
+			PyErr_SetString(CdError, "no disc in player");
+		else
+			PyErr_SetString(CdError, "playabs failed");
+		return NULL;
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+	
+static PyObject *
+CD_playtrack(cdplayerobject *self, PyObject *args)
+{
+	int start, play;
+	CDSTATUS status;
+
+	if (!PyArg_ParseTuple(args, "ii:playtrack", &start, &play))
+		return NULL;
+
+	if (!CDplaytrack(self->ob_cdplayer, start, play)) {
+		if (CDgetstatus(self->ob_cdplayer, &status) &&
+		    status.state == CD_NODISC)
+			PyErr_SetString(CdError, "no disc in player");
+		else
+			PyErr_SetString(CdError, "playtrack failed");
+		return NULL;
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+	
+static PyObject *
+CD_playtrackabs(cdplayerobject *self, PyObject *args)
+{
+	int track, min, sec, frame, play;
+	CDSTATUS status;
+
+	if (!PyArg_ParseTuple(args, "iiiii:playtrackabs", &track, &min, &sec,
+			      &frame, &play))
+		return NULL;
+
+	if (!CDplaytrackabs(self->ob_cdplayer, track, min, sec, frame, play)) {
+		if (CDgetstatus(self->ob_cdplayer, &status) &&
+		    status.state == CD_NODISC)
+			PyErr_SetString(CdError, "no disc in player");
+		else
+			PyErr_SetString(CdError, "playtrackabs failed");
+		return NULL;
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+	
+static PyObject *
+CD_readda(cdplayerobject *self, PyObject *args)
+{
+	int numframes, n;
+	PyObject *result;
+
+	if (!PyArg_ParseTuple(args, "i:readda", &numframes))
+		return NULL;
+
+	result = PyString_FromStringAndSize(NULL, numframes * sizeof(CDFRAME));
+	if (result == NULL)
+		return NULL;
+
+	n = CDreadda(self->ob_cdplayer,
+		       (CDFRAME *) PyString_AsString(result), numframes);
+	if (n == -1) {
+		Py_DECREF(result);
+		PyErr_SetFromErrno(CdError);
+		return NULL;
+	}
+	if (n < numframes)
+		_PyString_Resize(&result, n * sizeof(CDFRAME));
+
+	return result;
+}
+
+static PyObject *
+CD_seek(cdplayerobject *self, PyObject *args)
+{
+	int min, sec, frame;
+	long PyTryBlock;
+
+	if (!PyArg_ParseTuple(args, "iii:seek", &min, &sec, &frame))
+		return NULL;
+
+	PyTryBlock = CDseek(self->ob_cdplayer, min, sec, frame);
+	if (PyTryBlock == -1) {
+		PyErr_SetFromErrno(CdError);
+		return NULL;
+	}
+
+	return PyInt_FromLong(PyTryBlock);
+}
+	
+static PyObject *
+CD_seektrack(cdplayerobject *self, PyObject *args)
+{
+	int track;
+	long PyTryBlock;
+
+	if (!PyArg_ParseTuple(args, "i:seektrack", &track))
+		return NULL;
+
+	PyTryBlock = CDseektrack(self->ob_cdplayer, track);
+	if (PyTryBlock == -1) {
+		PyErr_SetFromErrno(CdError);
+		return NULL;
+	}
+
+	return PyInt_FromLong(PyTryBlock);
+}
+	
+static PyObject *
+CD_seekblock(cdplayerobject *self, PyObject *args)
+{
+	unsigned long PyTryBlock;
+
+	if (!PyArg_ParseTuple(args, "l:seekblock", &PyTryBlock))
+		return NULL;
+
+	PyTryBlock = CDseekblock(self->ob_cdplayer, PyTryBlock);
+	if (PyTryBlock == (unsigned long) -1) {
+		PyErr_SetFromErrno(CdError);
+		return NULL;
+	}
+
+	return PyInt_FromLong(PyTryBlock);
+}
+	
+static PyObject *
+CD_stop(cdplayerobject *self, PyObject *args)
+{
+	CDSTATUS status;
+
+	if (!PyArg_ParseTuple(args, ":stop"))
+		return NULL;
+
+	if (!CDstop(self->ob_cdplayer)) {
+		if (CDgetstatus(self->ob_cdplayer, &status) &&
+		    status.state == CD_NODISC)
+			PyErr_SetString(CdError, "no disc in player");
+		else
+			PyErr_SetString(CdError, "stop failed");
+		return NULL;
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+	
+static PyObject *
+CD_togglepause(cdplayerobject *self, PyObject *args)
+{
+	CDSTATUS status;
+
+	if (!PyArg_ParseTuple(args, ":togglepause"))
+		return NULL;
+
+	if (!CDtogglepause(self->ob_cdplayer)) {
+		if (CDgetstatus(self->ob_cdplayer, &status) &&
+		    status.state == CD_NODISC)
+			PyErr_SetString(CdError, "no disc in player");
+		else
+			PyErr_SetString(CdError, "togglepause failed");
+		return NULL;
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+	
+static PyMethodDef cdplayer_methods[] = {
+	{"allowremoval",	(PyCFunction)CD_allowremoval,	METH_VARARGS},
+	{"bestreadsize",	(PyCFunction)CD_bestreadsize,	METH_VARARGS},
+	{"close",		(PyCFunction)CD_close,		METH_VARARGS},
+	{"eject",		(PyCFunction)CD_eject,		METH_VARARGS},
+	{"getstatus",		(PyCFunction)CD_getstatus,		METH_VARARGS},
+	{"gettrackinfo",	(PyCFunction)CD_gettrackinfo,	METH_VARARGS},
+	{"msftoblock",		(PyCFunction)CD_msftoblock,		METH_VARARGS},
+	{"play",		(PyCFunction)CD_play,		METH_VARARGS},
+	{"playabs",		(PyCFunction)CD_playabs,		METH_VARARGS},
+	{"playtrack",		(PyCFunction)CD_playtrack,		METH_VARARGS},
+	{"playtrackabs",	(PyCFunction)CD_playtrackabs,	METH_VARARGS},
+	{"preventremoval",	(PyCFunction)CD_preventremoval,	METH_VARARGS},
+	{"readda",		(PyCFunction)CD_readda,		METH_VARARGS},
+	{"seek",		(PyCFunction)CD_seek,		METH_VARARGS},
+	{"seekblock",		(PyCFunction)CD_seekblock,		METH_VARARGS},
+	{"seektrack",		(PyCFunction)CD_seektrack,		METH_VARARGS},
+	{"stop",		(PyCFunction)CD_stop,		METH_VARARGS},
+	{"togglepause",		(PyCFunction)CD_togglepause,   	METH_VARARGS},
+	{NULL,			NULL} 		/* sentinel */
+};
+
+static void
+cdplayer_dealloc(cdplayerobject *self)
+{
+	if (self->ob_cdplayer != NULL)
+		CDclose(self->ob_cdplayer);
+	PyObject_Del(self);
+}
+
+static PyObject *
+cdplayer_getattr(cdplayerobject *self, char *name)
+{
+	if (self->ob_cdplayer == NULL) {
+		PyErr_SetString(PyExc_RuntimeError, "no player active");
+		return NULL;
+	}
+	return Py_FindMethod(cdplayer_methods, (PyObject *)self, name);
+}
+
+PyTypeObject CdPlayertype = {
+	PyObject_HEAD_INIT(&PyType_Type)
+	0,			/*ob_size*/
+	"cd.cdplayer",	/*tp_name*/
+	sizeof(cdplayerobject),	/*tp_size*/
+	0,			/*tp_itemsize*/
+	/* methods */
+	(destructor)cdplayer_dealloc, /*tp_dealloc*/
+	0,			/*tp_print*/
+	(getattrfunc)cdplayer_getattr, /*tp_getattr*/
+	0,			/*tp_setattr*/
+	0,			/*tp_compare*/
+	0,			/*tp_repr*/
+};
+
+static PyObject *
+newcdplayerobject(CDPLAYER *cdp)
+{
+	cdplayerobject *p;
+
+	p = PyObject_New(cdplayerobject, &CdPlayertype);
+	if (p == NULL)
+		return NULL;
+	p->ob_cdplayer = cdp;
+	return (PyObject *) p;
+}
+
+static PyObject *
+CD_open(PyObject *self, PyObject *args)
+{
+	char *dev, *direction;
+	CDPLAYER *cdp;
+
+	/*
+	 * Variable number of args.
+	 * First defaults to "None", second defaults to "r".
+	 */
+	dev = NULL;
+	direction = "r";
+	if (!PyArg_ParseTuple(args, "|zs:open", &dev, &direction))
+		return NULL;
+
+	cdp = CDopen(dev, direction);
+	if (cdp == NULL) {
+		PyErr_SetFromErrno(CdError);
+		return NULL;
+	}
+
+	return newcdplayerobject(cdp);
+}
+
+typedef struct {
+	PyObject_HEAD
+	CDPARSER *ob_cdparser;
+	struct {
+		PyObject *ob_cdcallback;
+		PyObject *ob_cdcallbackarg;
+	} ob_cdcallbacks[NCALLBACKS];
+} cdparserobject;
+
+static void
+CD_callback(void *arg, CDDATATYPES type, void *data)
+{
+	PyObject *result, *args, *v = NULL;
+	char *p;
+	int i;
+	cdparserobject *self;
+
+	self = (cdparserobject *) arg;
+	args = PyTuple_New(3);
+	if (args == NULL)
+		return;
+	Py_INCREF(self->ob_cdcallbacks[type].ob_cdcallbackarg);
+	PyTuple_SetItem(args, 0, self->ob_cdcallbacks[type].ob_cdcallbackarg);
+	PyTuple_SetItem(args, 1, PyInt_FromLong((long) type));
+	switch (type) {
+	case cd_audio:
+		v = PyString_FromStringAndSize(data, CDDA_DATASIZE);
+		break;
+	case cd_pnum:
+	case cd_index:
+		v = PyInt_FromLong(((CDPROGNUM *) data)->value);
+		break;
+	case cd_ptime:
+	case cd_atime:
+#define ptr ((struct cdtimecode *) data)
+		v = Py_BuildValue("(iii)",
+			    ptr->mhi * 10 + ptr->mlo,
+			    ptr->shi * 10 + ptr->slo,
+			    ptr->fhi * 10 + ptr->flo);
+#undef ptr
+		break;
+	case cd_catalog:
+		v = PyString_FromStringAndSize(NULL, 13);
+		p = PyString_AsString(v);
+		for (i = 0; i < 13; i++)
+			*p++ = ((char *) data)[i] + '0';
+		break;
+	case cd_ident:
+#define ptr ((struct cdident *) data)
+		v = PyString_FromStringAndSize(NULL, 12);
+		p = PyString_AsString(v);
+		CDsbtoa(p, ptr->country, 2);
+		p += 2;
+		CDsbtoa(p, ptr->owner, 3);
+		p += 3;
+		*p++ = ptr->year[0] + '0';
+		*p++ = ptr->year[1] + '0';
+		*p++ = ptr->serial[0] + '0';
+		*p++ = ptr->serial[1] + '0';
+		*p++ = ptr->serial[2] + '0';
+		*p++ = ptr->serial[3] + '0';
+		*p++ = ptr->serial[4] + '0';
+#undef ptr
+		break;
+	case cd_control:
+		v = PyInt_FromLong((long) *((unchar *) data));
+		break;
+	}
+	PyTuple_SetItem(args, 2, v);
+	if (PyErr_Occurred()) {
+		Py_DECREF(args);
+		return;
+	}
+	
+	result = PyEval_CallObject(self->ob_cdcallbacks[type].ob_cdcallback,
+				   args);
+	Py_DECREF(args);
+	Py_XDECREF(result);
+}
+
+static PyObject *
+CD_deleteparser(cdparserobject *self, PyObject *args)
+{
+	int i;
+
+	if (!PyArg_ParseTuple(args, ":deleteparser"))
+		return NULL;
+
+	CDdeleteparser(self->ob_cdparser);
+	self->ob_cdparser = NULL;
+
+	/* no sense in keeping the callbacks, so remove them */
+	for (i = 0; i < NCALLBACKS; i++) {
+		Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallback);
+		self->ob_cdcallbacks[i].ob_cdcallback = NULL;
+		Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallbackarg);
+		self->ob_cdcallbacks[i].ob_cdcallbackarg = NULL;
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *
+CD_parseframe(cdparserobject *self, PyObject *args)
+{
+	char *cdfp;
+	int length;
+	CDFRAME *p;
+
+	if (!PyArg_ParseTuple(args, "s#:parseframe", &cdfp, &length))
+		return NULL;
+
+	if (length % sizeof(CDFRAME) != 0) {
+		PyErr_SetString(PyExc_TypeError, "bad length");
+		return NULL;
+	}
+
+	p = (CDFRAME *) cdfp;
+	while (length > 0) {
+		CDparseframe(self->ob_cdparser, p);
+		length -= sizeof(CDFRAME);
+		p++;
+		if (PyErr_Occurred())
+			return NULL;
+	}
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *
+CD_removecallback(cdparserobject *self, PyObject *args)
+{
+	int type;
+
+	if (!PyArg_ParseTuple(args, "i:removecallback", &type))
+		return NULL;
+
+	if (type < 0 || type >= NCALLBACKS) {
+		PyErr_SetString(PyExc_TypeError, "bad type");
+		return NULL;
+	}
+
+	CDremovecallback(self->ob_cdparser, (CDDATATYPES) type);
+
+	Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallback);
+	self->ob_cdcallbacks[type].ob_cdcallback = NULL;
+
+	Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallbackarg);
+	self->ob_cdcallbacks[type].ob_cdcallbackarg = NULL;
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *
+CD_resetparser(cdparserobject *self, PyObject *args)
+{
+	if (!PyArg_ParseTuple(args, ":resetparser"))
+		return NULL;
+
+	CDresetparser(self->ob_cdparser);
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyObject *
+CD_addcallback(cdparserobject *self, PyObject *args)
+{
+	int type;
+	PyObject *func, *funcarg;
+
+	/* XXX - more work here */
+	if (!PyArg_ParseTuple(args, "iOO:addcallback", &type, &func, &funcarg))
+		return NULL;
+
+	if (type < 0 || type >= NCALLBACKS) {
+		PyErr_SetString(PyExc_TypeError, "argument out of range");
+		return NULL;
+	}
+
+#ifdef CDsetcallback
+	CDaddcallback(self->ob_cdparser, (CDDATATYPES) type, CD_callback,
+		      (void *) self);
+#else
+	CDsetcallback(self->ob_cdparser, (CDDATATYPES) type, CD_callback,
+		      (void *) self);
+#endif
+	Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallback);
+	Py_INCREF(func);
+	self->ob_cdcallbacks[type].ob_cdcallback = func;
+	Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallbackarg);
+	Py_INCREF(funcarg);
+	self->ob_cdcallbacks[type].ob_cdcallbackarg = funcarg;
+
+/*
+	if (type == cd_audio) {
+		sigfpe_[_UNDERFL].repls = _ZERO;
+		handle_sigfpes(_ON, _EN_UNDERFL, NULL,
+		                        _ABORT_ON_ERROR, NULL);
+	}
+*/
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyMethodDef cdparser_methods[] = {
+	{"addcallback",		(PyCFunction)CD_addcallback,   	METH_VARARGS},
+	{"deleteparser",	(PyCFunction)CD_deleteparser,	METH_VARARGS},
+	{"parseframe",		(PyCFunction)CD_parseframe,	METH_VARARGS},
+	{"removecallback",	(PyCFunction)CD_removecallback,	METH_VARARGS},
+	{"resetparser",		(PyCFunction)CD_resetparser,	METH_VARARGS},
+		                                /* backward compatibility */
+	{"setcallback",		(PyCFunction)CD_addcallback,   	METH_VARARGS},
+	{NULL,			NULL} 		/* sentinel */
+};
+
+static void
+cdparser_dealloc(cdparserobject *self)
+{
+	int i;
+
+	for (i = 0; i < NCALLBACKS; i++) {
+		Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallback);
+		self->ob_cdcallbacks[i].ob_cdcallback = NULL;
+		Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallbackarg);
+		self->ob_cdcallbacks[i].ob_cdcallbackarg = NULL;
+	}
+	CDdeleteparser(self->ob_cdparser);
+	PyObject_Del(self);
+}
+
+static PyObject *
+cdparser_getattr(cdparserobject *self, char *name)
+{
+	if (self->ob_cdparser == NULL) {
+		PyErr_SetString(PyExc_RuntimeError, "no parser active");
+		return NULL;
+	}
+
+	return Py_FindMethod(cdparser_methods, (PyObject *)self, name);
+}
+
+PyTypeObject CdParsertype = {
+	PyObject_HEAD_INIT(&PyType_Type)
+	0,			/*ob_size*/
+	"cd.cdparser",		/*tp_name*/
+	sizeof(cdparserobject),	/*tp_size*/
+	0,			/*tp_itemsize*/
+	/* methods */
+	(destructor)cdparser_dealloc, /*tp_dealloc*/
+	0,			/*tp_print*/
+	(getattrfunc)cdparser_getattr, /*tp_getattr*/
+	0,			/*tp_setattr*/
+	0,			/*tp_compare*/
+	0,			/*tp_repr*/
+};
+
+static PyObject *
+newcdparserobject(CDPARSER *cdp)
+{
+	cdparserobject *p;
+	int i;
+
+	p = PyObject_New(cdparserobject, &CdParsertype);
+	if (p == NULL)
+		return NULL;
+	p->ob_cdparser = cdp;
+	for (i = 0; i < NCALLBACKS; i++) {
+		p->ob_cdcallbacks[i].ob_cdcallback = NULL;
+		p->ob_cdcallbacks[i].ob_cdcallbackarg = NULL;
+	}
+	return (PyObject *) p;
+}
+
+static PyObject *
+CD_createparser(PyObject *self, PyObject *args)
+{
+	CDPARSER *cdp;
+
+	if (!PyArg_ParseTuple(args, ":createparser"))
+		return NULL;
+	cdp = CDcreateparser();
+	if (cdp == NULL) {
+		PyErr_SetString(CdError, "createparser failed");
+		return NULL;
+	}
+
+	return newcdparserobject(cdp);
+}
+
+static PyObject *
+CD_msftoframe(PyObject *self, PyObject *args)
+{
+	int min, sec, frame;
+
+	if (!PyArg_ParseTuple(args, "iii:msftoframe", &min, &sec, &frame))
+		return NULL;
+
+	return PyInt_FromLong((long) CDmsftoframe(min, sec, frame));
+}
+	
+static PyMethodDef CD_methods[] = {
+	{"open",		(PyCFunction)CD_open,		METH_VARARGS},
+	{"createparser",	(PyCFunction)CD_createparser,	METH_VARARGS},
+	{"msftoframe",		(PyCFunction)CD_msftoframe,	METH_VARARGS},
+	{NULL,		NULL}	/* Sentinel */
+};
+
+void
+initcd(void)
+{
+	PyObject *m, *d;
+	
+	if (PyErr_WarnPy3k("the cd module has been removed in "
+	                   "Python 3.0", 2) < 0)
+	    return;
+
+	m = Py_InitModule("cd", CD_methods);
+	if (m == NULL)
+		return;
+	d = PyModule_GetDict(m);
+
+	CdError = PyErr_NewException("cd.error", NULL, NULL);
+	PyDict_SetItemString(d, "error", CdError);
+
+	/* Identifiers for the different types of callbacks from the parser */
+	PyDict_SetItemString(d, "audio", PyInt_FromLong((long) cd_audio));
+	PyDict_SetItemString(d, "pnum", PyInt_FromLong((long) cd_pnum));
+	PyDict_SetItemString(d, "index", PyInt_FromLong((long) cd_index));
+	PyDict_SetItemString(d, "ptime", PyInt_FromLong((long) cd_ptime));
+	PyDict_SetItemString(d, "atime", PyInt_FromLong((long) cd_atime));
+	PyDict_SetItemString(d, "catalog", PyInt_FromLong((long) cd_catalog));
+	PyDict_SetItemString(d, "ident", PyInt_FromLong((long) cd_ident));
+	PyDict_SetItemString(d, "control", PyInt_FromLong((long) cd_control));
+
+	/* Block size information for digital audio data */
+	PyDict_SetItemString(d, "DATASIZE",
+			   PyInt_FromLong((long) CDDA_DATASIZE));
+	PyDict_SetItemString(d, "BLOCKSIZE",
+			   PyInt_FromLong((long) CDDA_BLOCKSIZE));
+
+	/* Possible states for the cd player */
+	PyDict_SetItemString(d, "ERROR", PyInt_FromLong((long) CD_ERROR));
+	PyDict_SetItemString(d, "NODISC", PyInt_FromLong((long) CD_NODISC));
+	PyDict_SetItemString(d, "READY", PyInt_FromLong((long) CD_READY));
+	PyDict_SetItemString(d, "PLAYING", PyInt_FromLong((long) CD_PLAYING));
+	PyDict_SetItemString(d, "PAUSED", PyInt_FromLong((long) CD_PAUSED));
+	PyDict_SetItemString(d, "STILL", PyInt_FromLong((long) CD_STILL));
+#ifdef CD_CDROM			/* only newer versions of the library */
+	PyDict_SetItemString(d, "CDROM", PyInt_FromLong((long) CD_CDROM));
+#endif
+}