1 /* CD module -- interface to Mark Callow's and Roger Chickering's */
2  /* CD Audio Library (CD). */
3 
4 #include <sys/types.h>
5 #include <cdaudio.h>
6 #include "Python.h"
7 
8 #define NCALLBACKS      8
9 
10 typedef struct {
11     PyObject_HEAD
12     CDPLAYER *ob_cdplayer;
13 } cdplayerobject;
14 
15 static PyObject *CdError;               /* exception cd.error */
16 
17 static PyObject *
CD_allowremoval(cdplayerobject * self,PyObject * args)18 CD_allowremoval(cdplayerobject *self, PyObject *args)
19 {
20     if (!PyArg_ParseTuple(args, ":allowremoval"))
21         return NULL;
22 
23     CDallowremoval(self->ob_cdplayer);
24 
25     Py_INCREF(Py_None);
26     return Py_None;
27 }
28 
29 static PyObject *
CD_preventremoval(cdplayerobject * self,PyObject * args)30 CD_preventremoval(cdplayerobject *self, PyObject *args)
31 {
32     if (!PyArg_ParseTuple(args, ":preventremoval"))
33         return NULL;
34 
35     CDpreventremoval(self->ob_cdplayer);
36 
37     Py_INCREF(Py_None);
38     return Py_None;
39 }
40 
41 static PyObject *
CD_bestreadsize(cdplayerobject * self,PyObject * args)42 CD_bestreadsize(cdplayerobject *self, PyObject *args)
43 {
44     if (!PyArg_ParseTuple(args, ":bestreadsize"))
45         return NULL;
46 
47     return PyInt_FromLong((long) CDbestreadsize(self->ob_cdplayer));
48 }
49 
50 static PyObject *
CD_close(cdplayerobject * self,PyObject * args)51 CD_close(cdplayerobject *self, PyObject *args)
52 {
53     if (!PyArg_ParseTuple(args, ":close"))
54         return NULL;
55 
56     if (!CDclose(self->ob_cdplayer)) {
57         PyErr_SetFromErrno(CdError); /* XXX - ??? */
58         return NULL;
59     }
60     self->ob_cdplayer = NULL;
61 
62     Py_INCREF(Py_None);
63     return Py_None;
64 }
65 
66 static PyObject *
CD_eject(cdplayerobject * self,PyObject * args)67 CD_eject(cdplayerobject *self, PyObject *args)
68 {
69     CDSTATUS status;
70 
71     if (!PyArg_ParseTuple(args, ":eject"))
72         return NULL;
73 
74     if (!CDeject(self->ob_cdplayer)) {
75         if (CDgetstatus(self->ob_cdplayer, &status) &&
76             status.state == CD_NODISC)
77             PyErr_SetString(CdError, "no disc in player");
78         else
79             PyErr_SetString(CdError, "eject failed");
80         return NULL;
81     }
82 
83     Py_INCREF(Py_None);
84     return Py_None;
85 }
86 
87 static PyObject *
CD_getstatus(cdplayerobject * self,PyObject * args)88 CD_getstatus(cdplayerobject *self, PyObject *args)
89 {
90     CDSTATUS status;
91 
92     if (!PyArg_ParseTuple(args, ":getstatus"))
93         return NULL;
94 
95     if (!CDgetstatus(self->ob_cdplayer, &status)) {
96         PyErr_SetFromErrno(CdError); /* XXX - ??? */
97         return NULL;
98     }
99 
100     return Py_BuildValue("(ii(iii)(iii)(iii)iiii)", status.state,
101                    status.track, status.min, status.sec, status.frame,
102                    status.abs_min, status.abs_sec, status.abs_frame,
103                    status.total_min, status.total_sec, status.total_frame,
104                    status.first, status.last, status.scsi_audio,
105                    status.cur_block);
106 }
107 
108 static PyObject *
CD_gettrackinfo(cdplayerobject * self,PyObject * args)109 CD_gettrackinfo(cdplayerobject *self, PyObject *args)
110 {
111     int track;
112     CDTRACKINFO info;
113     CDSTATUS status;
114 
115     if (!PyArg_ParseTuple(args, "i:gettrackinfo", &track))
116         return NULL;
117 
118     if (!CDgettrackinfo(self->ob_cdplayer, track, &info)) {
119         if (CDgetstatus(self->ob_cdplayer, &status) &&
120             status.state == CD_NODISC)
121             PyErr_SetString(CdError, "no disc in player");
122         else
123             PyErr_SetString(CdError, "gettrackinfo failed");
124         return NULL;
125     }
126 
127     return Py_BuildValue("((iii)(iii))",
128                    info.start_min, info.start_sec, info.start_frame,
129                    info.total_min, info.total_sec, info.total_frame);
130 }
131 
132 static PyObject *
CD_msftoblock(cdplayerobject * self,PyObject * args)133 CD_msftoblock(cdplayerobject *self, PyObject *args)
134 {
135     int min, sec, frame;
136 
137     if (!PyArg_ParseTuple(args, "iii:msftoblock", &min, &sec, &frame))
138         return NULL;
139 
140     return PyInt_FromLong((long) CDmsftoblock(self->ob_cdplayer,
141                                             min, sec, frame));
142 }
143 
144 static PyObject *
CD_play(cdplayerobject * self,PyObject * args)145 CD_play(cdplayerobject *self, PyObject *args)
146 {
147     int start, play;
148     CDSTATUS status;
149 
150     if (!PyArg_ParseTuple(args, "ii:play", &start, &play))
151         return NULL;
152 
153     if (!CDplay(self->ob_cdplayer, start, play)) {
154         if (CDgetstatus(self->ob_cdplayer, &status) &&
155             status.state == CD_NODISC)
156             PyErr_SetString(CdError, "no disc in player");
157         else
158             PyErr_SetString(CdError, "play failed");
159         return NULL;
160     }
161 
162     Py_INCREF(Py_None);
163     return Py_None;
164 }
165 
166 static PyObject *
CD_playabs(cdplayerobject * self,PyObject * args)167 CD_playabs(cdplayerobject *self, PyObject *args)
168 {
169     int min, sec, frame, play;
170     CDSTATUS status;
171 
172     if (!PyArg_ParseTuple(args, "iiii:playabs", &min, &sec, &frame, &play))
173         return NULL;
174 
175     if (!CDplayabs(self->ob_cdplayer, min, sec, frame, play)) {
176         if (CDgetstatus(self->ob_cdplayer, &status) &&
177             status.state == CD_NODISC)
178             PyErr_SetString(CdError, "no disc in player");
179         else
180             PyErr_SetString(CdError, "playabs failed");
181         return NULL;
182     }
183 
184     Py_INCREF(Py_None);
185     return Py_None;
186 }
187 
188 static PyObject *
CD_playtrack(cdplayerobject * self,PyObject * args)189 CD_playtrack(cdplayerobject *self, PyObject *args)
190 {
191     int start, play;
192     CDSTATUS status;
193 
194     if (!PyArg_ParseTuple(args, "ii:playtrack", &start, &play))
195         return NULL;
196 
197     if (!CDplaytrack(self->ob_cdplayer, start, play)) {
198         if (CDgetstatus(self->ob_cdplayer, &status) &&
199             status.state == CD_NODISC)
200             PyErr_SetString(CdError, "no disc in player");
201         else
202             PyErr_SetString(CdError, "playtrack failed");
203         return NULL;
204     }
205 
206     Py_INCREF(Py_None);
207     return Py_None;
208 }
209 
210 static PyObject *
CD_playtrackabs(cdplayerobject * self,PyObject * args)211 CD_playtrackabs(cdplayerobject *self, PyObject *args)
212 {
213     int track, min, sec, frame, play;
214     CDSTATUS status;
215 
216     if (!PyArg_ParseTuple(args, "iiiii:playtrackabs", &track, &min, &sec,
217                           &frame, &play))
218         return NULL;
219 
220     if (!CDplaytrackabs(self->ob_cdplayer, track, min, sec, frame, play)) {
221         if (CDgetstatus(self->ob_cdplayer, &status) &&
222             status.state == CD_NODISC)
223             PyErr_SetString(CdError, "no disc in player");
224         else
225             PyErr_SetString(CdError, "playtrackabs failed");
226         return NULL;
227     }
228 
229     Py_INCREF(Py_None);
230     return Py_None;
231 }
232 
233 static PyObject *
CD_readda(cdplayerobject * self,PyObject * args)234 CD_readda(cdplayerobject *self, PyObject *args)
235 {
236     int numframes, n;
237     PyObject *result;
238 
239     if (!PyArg_ParseTuple(args, "i:readda", &numframes))
240         return NULL;
241 
242     result = PyString_FromStringAndSize(NULL, numframes * sizeof(CDFRAME));
243     if (result == NULL)
244         return NULL;
245 
246     n = CDreadda(self->ob_cdplayer,
247                    (CDFRAME *) PyString_AsString(result), numframes);
248     if (n == -1) {
249         Py_DECREF(result);
250         PyErr_SetFromErrno(CdError);
251         return NULL;
252     }
253     if (n < numframes)
254         _PyString_Resize(&result, n * sizeof(CDFRAME));
255 
256     return result;
257 }
258 
259 static PyObject *
CD_seek(cdplayerobject * self,PyObject * args)260 CD_seek(cdplayerobject *self, PyObject *args)
261 {
262     int min, sec, frame;
263     long PyTryBlock;
264 
265     if (!PyArg_ParseTuple(args, "iii:seek", &min, &sec, &frame))
266         return NULL;
267 
268     PyTryBlock = CDseek(self->ob_cdplayer, min, sec, frame);
269     if (PyTryBlock == -1) {
270         PyErr_SetFromErrno(CdError);
271         return NULL;
272     }
273 
274     return PyInt_FromLong(PyTryBlock);
275 }
276 
277 static PyObject *
CD_seektrack(cdplayerobject * self,PyObject * args)278 CD_seektrack(cdplayerobject *self, PyObject *args)
279 {
280     int track;
281     long PyTryBlock;
282 
283     if (!PyArg_ParseTuple(args, "i:seektrack", &track))
284         return NULL;
285 
286     PyTryBlock = CDseektrack(self->ob_cdplayer, track);
287     if (PyTryBlock == -1) {
288         PyErr_SetFromErrno(CdError);
289         return NULL;
290     }
291 
292     return PyInt_FromLong(PyTryBlock);
293 }
294 
295 static PyObject *
CD_seekblock(cdplayerobject * self,PyObject * args)296 CD_seekblock(cdplayerobject *self, PyObject *args)
297 {
298     unsigned long PyTryBlock;
299 
300     if (!PyArg_ParseTuple(args, "l:seekblock", &PyTryBlock))
301         return NULL;
302 
303     PyTryBlock = CDseekblock(self->ob_cdplayer, PyTryBlock);
304     if (PyTryBlock == (unsigned long) -1) {
305         PyErr_SetFromErrno(CdError);
306         return NULL;
307     }
308 
309     return PyInt_FromLong(PyTryBlock);
310 }
311 
312 static PyObject *
CD_stop(cdplayerobject * self,PyObject * args)313 CD_stop(cdplayerobject *self, PyObject *args)
314 {
315     CDSTATUS status;
316 
317     if (!PyArg_ParseTuple(args, ":stop"))
318         return NULL;
319 
320     if (!CDstop(self->ob_cdplayer)) {
321         if (CDgetstatus(self->ob_cdplayer, &status) &&
322             status.state == CD_NODISC)
323             PyErr_SetString(CdError, "no disc in player");
324         else
325             PyErr_SetString(CdError, "stop failed");
326         return NULL;
327     }
328 
329     Py_INCREF(Py_None);
330     return Py_None;
331 }
332 
333 static PyObject *
CD_togglepause(cdplayerobject * self,PyObject * args)334 CD_togglepause(cdplayerobject *self, PyObject *args)
335 {
336     CDSTATUS status;
337 
338     if (!PyArg_ParseTuple(args, ":togglepause"))
339         return NULL;
340 
341     if (!CDtogglepause(self->ob_cdplayer)) {
342         if (CDgetstatus(self->ob_cdplayer, &status) &&
343             status.state == CD_NODISC)
344             PyErr_SetString(CdError, "no disc in player");
345         else
346             PyErr_SetString(CdError, "togglepause failed");
347         return NULL;
348     }
349 
350     Py_INCREF(Py_None);
351     return Py_None;
352 }
353 
354 static PyMethodDef cdplayer_methods[] = {
355     {"allowremoval",            (PyCFunction)CD_allowremoval,   METH_VARARGS},
356     {"bestreadsize",            (PyCFunction)CD_bestreadsize,   METH_VARARGS},
357     {"close",                   (PyCFunction)CD_close,          METH_VARARGS},
358     {"eject",                   (PyCFunction)CD_eject,          METH_VARARGS},
359     {"getstatus",               (PyCFunction)CD_getstatus,              METH_VARARGS},
360     {"gettrackinfo",            (PyCFunction)CD_gettrackinfo,   METH_VARARGS},
361     {"msftoblock",              (PyCFunction)CD_msftoblock,             METH_VARARGS},
362     {"play",                    (PyCFunction)CD_play,           METH_VARARGS},
363     {"playabs",                 (PyCFunction)CD_playabs,                METH_VARARGS},
364     {"playtrack",               (PyCFunction)CD_playtrack,              METH_VARARGS},
365     {"playtrackabs",            (PyCFunction)CD_playtrackabs,   METH_VARARGS},
366     {"preventremoval",          (PyCFunction)CD_preventremoval, METH_VARARGS},
367     {"readda",                  (PyCFunction)CD_readda,         METH_VARARGS},
368     {"seek",                    (PyCFunction)CD_seek,           METH_VARARGS},
369     {"seekblock",               (PyCFunction)CD_seekblock,              METH_VARARGS},
370     {"seektrack",               (PyCFunction)CD_seektrack,              METH_VARARGS},
371     {"stop",                    (PyCFunction)CD_stop,           METH_VARARGS},
372     {"togglepause",             (PyCFunction)CD_togglepause,    METH_VARARGS},
373     {NULL,                      NULL}           /* sentinel */
374 };
375 
376 static void
cdplayer_dealloc(cdplayerobject * self)377 cdplayer_dealloc(cdplayerobject *self)
378 {
379     if (self->ob_cdplayer != NULL)
380         CDclose(self->ob_cdplayer);
381     PyObject_Del(self);
382 }
383 
384 static PyObject *
cdplayer_getattr(cdplayerobject * self,char * name)385 cdplayer_getattr(cdplayerobject *self, char *name)
386 {
387     if (self->ob_cdplayer == NULL) {
388         PyErr_SetString(PyExc_RuntimeError, "no player active");
389         return NULL;
390     }
391     return Py_FindMethod(cdplayer_methods, (PyObject *)self, name);
392 }
393 
394 PyTypeObject CdPlayertype = {
395     PyObject_HEAD_INIT(&PyType_Type)
396     0,                          /*ob_size*/
397     "cd.cdplayer",      /*tp_name*/
398     sizeof(cdplayerobject),     /*tp_size*/
399     0,                          /*tp_itemsize*/
400     /* methods */
401     (destructor)cdplayer_dealloc, /*tp_dealloc*/
402     0,                          /*tp_print*/
403     (getattrfunc)cdplayer_getattr, /*tp_getattr*/
404     0,                          /*tp_setattr*/
405     0,                          /*tp_compare*/
406     0,                          /*tp_repr*/
407 };
408 
409 static PyObject *
newcdplayerobject(CDPLAYER * cdp)410 newcdplayerobject(CDPLAYER *cdp)
411 {
412     cdplayerobject *p;
413 
414     p = PyObject_New(cdplayerobject, &CdPlayertype);
415     if (p == NULL)
416         return NULL;
417     p->ob_cdplayer = cdp;
418     return (PyObject *) p;
419 }
420 
421 static PyObject *
CD_open(PyObject * self,PyObject * args)422 CD_open(PyObject *self, PyObject *args)
423 {
424     char *dev, *direction;
425     CDPLAYER *cdp;
426 
427     /*
428      * Variable number of args.
429      * First defaults to "None", second defaults to "r".
430      */
431     dev = NULL;
432     direction = "r";
433     if (!PyArg_ParseTuple(args, "|zs:open", &dev, &direction))
434         return NULL;
435 
436     cdp = CDopen(dev, direction);
437     if (cdp == NULL) {
438         PyErr_SetFromErrno(CdError);
439         return NULL;
440     }
441 
442     return newcdplayerobject(cdp);
443 }
444 
445 typedef struct {
446     PyObject_HEAD
447     CDPARSER *ob_cdparser;
448     struct {
449         PyObject *ob_cdcallback;
450         PyObject *ob_cdcallbackarg;
451     } ob_cdcallbacks[NCALLBACKS];
452 } cdparserobject;
453 
454 static void
CD_callback(void * arg,CDDATATYPES type,void * data)455 CD_callback(void *arg, CDDATATYPES type, void *data)
456 {
457     PyObject *result, *args, *v = NULL;
458     char *p;
459     int i;
460     cdparserobject *self;
461 
462     self = (cdparserobject *) arg;
463     args = PyTuple_New(3);
464     if (args == NULL)
465         return;
466     Py_INCREF(self->ob_cdcallbacks[type].ob_cdcallbackarg);
467     PyTuple_SetItem(args, 0, self->ob_cdcallbacks[type].ob_cdcallbackarg);
468     PyTuple_SetItem(args, 1, PyInt_FromLong((long) type));
469     switch (type) {
470     case cd_audio:
471         v = PyString_FromStringAndSize(data, CDDA_DATASIZE);
472         break;
473     case cd_pnum:
474     case cd_index:
475         v = PyInt_FromLong(((CDPROGNUM *) data)->value);
476         break;
477     case cd_ptime:
478     case cd_atime:
479 #define ptr ((struct cdtimecode *) data)
480         v = Py_BuildValue("(iii)",
481                     ptr->mhi * 10 + ptr->mlo,
482                     ptr->shi * 10 + ptr->slo,
483                     ptr->fhi * 10 + ptr->flo);
484 #undef ptr
485         break;
486     case cd_catalog:
487         v = PyString_FromStringAndSize(NULL, 13);
488         p = PyString_AsString(v);
489         for (i = 0; i < 13; i++)
490             *p++ = ((char *) data)[i] + '0';
491         break;
492     case cd_ident:
493 #define ptr ((struct cdident *) data)
494         v = PyString_FromStringAndSize(NULL, 12);
495         p = PyString_AsString(v);
496         CDsbtoa(p, ptr->country, 2);
497         p += 2;
498         CDsbtoa(p, ptr->owner, 3);
499         p += 3;
500         *p++ = ptr->year[0] + '0';
501         *p++ = ptr->year[1] + '0';
502         *p++ = ptr->serial[0] + '0';
503         *p++ = ptr->serial[1] + '0';
504         *p++ = ptr->serial[2] + '0';
505         *p++ = ptr->serial[3] + '0';
506         *p++ = ptr->serial[4] + '0';
507 #undef ptr
508         break;
509     case cd_control:
510         v = PyInt_FromLong((long) *((unchar *) data));
511         break;
512     }
513     PyTuple_SetItem(args, 2, v);
514     if (PyErr_Occurred()) {
515         Py_DECREF(args);
516         return;
517     }
518 
519     result = PyEval_CallObject(self->ob_cdcallbacks[type].ob_cdcallback,
520                                args);
521     Py_DECREF(args);
522     Py_XDECREF(result);
523 }
524 
525 static PyObject *
CD_deleteparser(cdparserobject * self,PyObject * args)526 CD_deleteparser(cdparserobject *self, PyObject *args)
527 {
528     int i;
529 
530     if (!PyArg_ParseTuple(args, ":deleteparser"))
531         return NULL;
532 
533     CDdeleteparser(self->ob_cdparser);
534     self->ob_cdparser = NULL;
535 
536     /* no sense in keeping the callbacks, so remove them */
537     for (i = 0; i < NCALLBACKS; i++) {
538         Py_CLEAR(self->ob_cdcallbacks[i].ob_cdcallback);
539         Py_CLEAR(self->ob_cdcallbacks[i].ob_cdcallbackarg);
540     }
541 
542     Py_INCREF(Py_None);
543     return Py_None;
544 }
545 
546 static PyObject *
CD_parseframe(cdparserobject * self,PyObject * args)547 CD_parseframe(cdparserobject *self, PyObject *args)
548 {
549     char *cdfp;
550     int length;
551     CDFRAME *p;
552 
553     if (!PyArg_ParseTuple(args, "s#:parseframe", &cdfp, &length))
554         return NULL;
555 
556     if (length % sizeof(CDFRAME) != 0) {
557         PyErr_SetString(PyExc_TypeError, "bad length");
558         return NULL;
559     }
560 
561     p = (CDFRAME *) cdfp;
562     while (length > 0) {
563         CDparseframe(self->ob_cdparser, p);
564         length -= sizeof(CDFRAME);
565         p++;
566         if (PyErr_Occurred())
567             return NULL;
568     }
569 
570     Py_INCREF(Py_None);
571     return Py_None;
572 }
573 
574 static PyObject *
CD_removecallback(cdparserobject * self,PyObject * args)575 CD_removecallback(cdparserobject *self, PyObject *args)
576 {
577     int type;
578 
579     if (!PyArg_ParseTuple(args, "i:removecallback", &type))
580         return NULL;
581 
582     if (type < 0 || type >= NCALLBACKS) {
583         PyErr_SetString(PyExc_TypeError, "bad type");
584         return NULL;
585     }
586 
587     CDremovecallback(self->ob_cdparser, (CDDATATYPES) type);
588 
589     Py_CLEAR(self->ob_cdcallbacks[type].ob_cdcallback);
590 
591     Py_CLEAR(self->ob_cdcallbacks[type].ob_cdcallbackarg);
592 
593     Py_INCREF(Py_None);
594     return Py_None;
595 }
596 
597 static PyObject *
CD_resetparser(cdparserobject * self,PyObject * args)598 CD_resetparser(cdparserobject *self, PyObject *args)
599 {
600     if (!PyArg_ParseTuple(args, ":resetparser"))
601         return NULL;
602 
603     CDresetparser(self->ob_cdparser);
604 
605     Py_INCREF(Py_None);
606     return Py_None;
607 }
608 
609 static PyObject *
CD_addcallback(cdparserobject * self,PyObject * args)610 CD_addcallback(cdparserobject *self, PyObject *args)
611 {
612     int type;
613     PyObject *func, *funcarg;
614 
615     /* XXX - more work here */
616     if (!PyArg_ParseTuple(args, "iOO:addcallback", &type, &func, &funcarg))
617         return NULL;
618 
619     if (type < 0 || type >= NCALLBACKS) {
620         PyErr_SetString(PyExc_TypeError, "argument out of range");
621         return NULL;
622     }
623 
624 #ifdef CDsetcallback
625     CDaddcallback(self->ob_cdparser, (CDDATATYPES) type, CD_callback,
626                   (void *) self);
627 #else
628     CDsetcallback(self->ob_cdparser, (CDDATATYPES) type, CD_callback,
629                   (void *) self);
630 #endif
631     Py_INCREF(func);
632     Py_XSETREF(self->ob_cdcallbacks[type].ob_cdcallback, func);
633     Py_INCREF(funcarg);
634     Py_XSETREF(self->ob_cdcallbacks[type].ob_cdcallbackarg, funcarg);
635 
636 /*
637     if (type == cd_audio) {
638         sigfpe_[_UNDERFL].repls = _ZERO;
639         handle_sigfpes(_ON, _EN_UNDERFL, NULL,
640                                 _ABORT_ON_ERROR, NULL);
641     }
642 */
643 
644     Py_INCREF(Py_None);
645     return Py_None;
646 }
647 
648 static PyMethodDef cdparser_methods[] = {
649     {"addcallback",             (PyCFunction)CD_addcallback,    METH_VARARGS},
650     {"deleteparser",            (PyCFunction)CD_deleteparser,   METH_VARARGS},
651     {"parseframe",              (PyCFunction)CD_parseframe,     METH_VARARGS},
652     {"removecallback",          (PyCFunction)CD_removecallback, METH_VARARGS},
653     {"resetparser",             (PyCFunction)CD_resetparser,    METH_VARARGS},
654                                             /* backward compatibility */
655     {"setcallback",             (PyCFunction)CD_addcallback,    METH_VARARGS},
656     {NULL,                      NULL}           /* sentinel */
657 };
658 
659 static void
cdparser_dealloc(cdparserobject * self)660 cdparser_dealloc(cdparserobject *self)
661 {
662     int i;
663 
664     for (i = 0; i < NCALLBACKS; i++) {
665         Py_CLEAR(self->ob_cdcallbacks[i].ob_cdcallback);
666         Py_CLEAR(self->ob_cdcallbacks[i].ob_cdcallbackarg);
667     }
668     CDdeleteparser(self->ob_cdparser);
669     PyObject_Del(self);
670 }
671 
672 static PyObject *
cdparser_getattr(cdparserobject * self,char * name)673 cdparser_getattr(cdparserobject *self, char *name)
674 {
675     if (self->ob_cdparser == NULL) {
676         PyErr_SetString(PyExc_RuntimeError, "no parser active");
677         return NULL;
678     }
679 
680     return Py_FindMethod(cdparser_methods, (PyObject *)self, name);
681 }
682 
683 PyTypeObject CdParsertype = {
684     PyObject_HEAD_INIT(&PyType_Type)
685     0,                          /*ob_size*/
686     "cd.cdparser",              /*tp_name*/
687     sizeof(cdparserobject),     /*tp_size*/
688     0,                          /*tp_itemsize*/
689     /* methods */
690     (destructor)cdparser_dealloc, /*tp_dealloc*/
691     0,                          /*tp_print*/
692     (getattrfunc)cdparser_getattr, /*tp_getattr*/
693     0,                          /*tp_setattr*/
694     0,                          /*tp_compare*/
695     0,                          /*tp_repr*/
696 };
697 
698 static PyObject *
newcdparserobject(CDPARSER * cdp)699 newcdparserobject(CDPARSER *cdp)
700 {
701     cdparserobject *p;
702     int i;
703 
704     p = PyObject_New(cdparserobject, &CdParsertype);
705     if (p == NULL)
706         return NULL;
707     p->ob_cdparser = cdp;
708     for (i = 0; i < NCALLBACKS; i++) {
709         p->ob_cdcallbacks[i].ob_cdcallback = NULL;
710         p->ob_cdcallbacks[i].ob_cdcallbackarg = NULL;
711     }
712     return (PyObject *) p;
713 }
714 
715 static PyObject *
CD_createparser(PyObject * self,PyObject * args)716 CD_createparser(PyObject *self, PyObject *args)
717 {
718     CDPARSER *cdp;
719 
720     if (!PyArg_ParseTuple(args, ":createparser"))
721         return NULL;
722     cdp = CDcreateparser();
723     if (cdp == NULL) {
724         PyErr_SetString(CdError, "createparser failed");
725         return NULL;
726     }
727 
728     return newcdparserobject(cdp);
729 }
730 
731 static PyObject *
CD_msftoframe(PyObject * self,PyObject * args)732 CD_msftoframe(PyObject *self, PyObject *args)
733 {
734     int min, sec, frame;
735 
736     if (!PyArg_ParseTuple(args, "iii:msftoframe", &min, &sec, &frame))
737         return NULL;
738 
739     return PyInt_FromLong((long) CDmsftoframe(min, sec, frame));
740 }
741 
742 static PyMethodDef CD_methods[] = {
743     {"open",                    (PyCFunction)CD_open,           METH_VARARGS},
744     {"createparser",            (PyCFunction)CD_createparser,   METH_VARARGS},
745     {"msftoframe",              (PyCFunction)CD_msftoframe,     METH_VARARGS},
746     {NULL,              NULL}   /* Sentinel */
747 };
748 
749 void
initcd(void)750 initcd(void)
751 {
752     PyObject *m, *d;
753 
754     if (PyErr_WarnPy3k("the cd module has been removed in "
755                        "Python 3.0", 2) < 0)
756         return;
757 
758     m = Py_InitModule("cd", CD_methods);
759     if (m == NULL)
760         return;
761     d = PyModule_GetDict(m);
762 
763     CdError = PyErr_NewException("cd.error", NULL, NULL);
764     PyDict_SetItemString(d, "error", CdError);
765 
766     /* Identifiers for the different types of callbacks from the parser */
767     PyDict_SetItemString(d, "audio", PyInt_FromLong((long) cd_audio));
768     PyDict_SetItemString(d, "pnum", PyInt_FromLong((long) cd_pnum));
769     PyDict_SetItemString(d, "index", PyInt_FromLong((long) cd_index));
770     PyDict_SetItemString(d, "ptime", PyInt_FromLong((long) cd_ptime));
771     PyDict_SetItemString(d, "atime", PyInt_FromLong((long) cd_atime));
772     PyDict_SetItemString(d, "catalog", PyInt_FromLong((long) cd_catalog));
773     PyDict_SetItemString(d, "ident", PyInt_FromLong((long) cd_ident));
774     PyDict_SetItemString(d, "control", PyInt_FromLong((long) cd_control));
775 
776     /* Block size information for digital audio data */
777     PyDict_SetItemString(d, "DATASIZE",
778                        PyInt_FromLong((long) CDDA_DATASIZE));
779     PyDict_SetItemString(d, "BLOCKSIZE",
780                        PyInt_FromLong((long) CDDA_BLOCKSIZE));
781 
782     /* Possible states for the cd player */
783     PyDict_SetItemString(d, "ERROR", PyInt_FromLong((long) CD_ERROR));
784     PyDict_SetItemString(d, "NODISC", PyInt_FromLong((long) CD_NODISC));
785     PyDict_SetItemString(d, "READY", PyInt_FromLong((long) CD_READY));
786     PyDict_SetItemString(d, "PLAYING", PyInt_FromLong((long) CD_PLAYING));
787     PyDict_SetItemString(d, "PAUSED", PyInt_FromLong((long) CD_PAUSED));
788     PyDict_SetItemString(d, "STILL", PyInt_FromLong((long) CD_STILL));
789 #ifdef CD_CDROM                 /* only newer versions of the library */
790     PyDict_SetItemString(d, "CDROM", PyInt_FromLong((long) CD_CDROM));
791 #endif
792 }
793