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