|  | /* 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 | 
|  | } |