improve treatment of multi-line replies, ignore empty lines
[python/dscho.git] / Modules / cdmodule.c
blob3e095778aeef4e63d9204730015d93a2b9b69505
1 /**********************************************************
2 Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3 The Netherlands.
5 All Rights Reserved
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the names of Stichting Mathematisch
12 Centrum or CWI not be used in advertising or publicity pertaining to
13 distribution of the software without specific, written prior permission.
15 STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18 FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 ******************************************************************/
25 /* CD module -- interface to Mark Callow's and Roger Chickering's */
26 /* CD Audio Library (CD). */
28 #include <sys/types.h>
29 #include <cdaudio.h>
30 #include "allobjects.h"
31 #include "import.h"
32 #include "modsupport.h"
33 #include "ceval.h"
35 #define NCALLBACKS 8
37 typedef struct {
38 OB_HEAD
39 CDPLAYER *ob_cdplayer;
40 } cdplayerobject;
42 #define CheckPlayer(self) if ((self)->ob_cdplayer == NULL) { \
43 err_setstr(RuntimeError, "no player active"); \
44 return NULL; \
46 #define CheckParser(self) if ((self)->ob_cdparser == NULL) { \
47 err_setstr(RuntimeError, "no parser active"); \
48 return NULL; \
51 static object *CdError; /* exception cd.error */
53 static object *
54 CD_allowremoval(self, args)
55 cdplayerobject *self;
56 object *args;
58 CheckPlayer(self);
60 if (!getnoarg(args))
61 return NULL;
63 CDallowremoval(self->ob_cdplayer);
65 INCREF(None);
66 return None;
69 static object *
70 CD_preventremoval(self, args)
71 cdplayerobject *self;
72 object *args;
74 CheckPlayer(self);
76 if (!getnoarg(args))
77 return NULL;
79 CDpreventremoval(self->ob_cdplayer);
81 INCREF(None);
82 return None;
85 static object *
86 CD_bestreadsize(self, args)
87 cdplayerobject *self;
88 object *args;
90 CheckPlayer(self);
92 if (!getnoarg(args))
93 return NULL;
95 return newintobject((long) CDbestreadsize(self->ob_cdplayer));
98 static object *
99 CD_close(self, args)
100 cdplayerobject *self;
101 object *args;
103 CheckPlayer(self);
105 if (!getnoarg(args))
106 return NULL;
108 if (!CDclose(self->ob_cdplayer)) {
109 err_errno(CdError); /* XXX - ??? */
110 return NULL;
112 self->ob_cdplayer = NULL;
114 INCREF(None);
115 return None;
118 static object *
119 CD_eject(self, args)
120 cdplayerobject *self;
121 object *args;
123 CDSTATUS status;
125 CheckPlayer(self);
127 if (!getnoarg(args))
128 return NULL;
130 if (!CDeject(self->ob_cdplayer)) {
131 if (CDgetstatus(self->ob_cdplayer, &status) &&
132 status.state == CD_NODISC)
133 err_setstr(CdError, "no disc in player");
134 else
135 err_setstr(CdError, "eject failed");
136 return NULL;
139 INCREF(None);
140 return None;
143 static object *
144 CD_getstatus(self, args)
145 cdplayerobject *self;
146 object *args;
148 CDSTATUS status;
150 CheckPlayer(self);
152 if (!getnoarg(args))
153 return NULL;
155 if (!CDgetstatus(self->ob_cdplayer, &status)) {
156 err_errno(CdError); /* XXX - ??? */
157 return NULL;
160 return mkvalue("(ii(iii)(iii)(iii)iiii(iii))", status.state,
161 status.track, status.min, status.sec, status.frame,
162 status.abs_min, status.abs_sec, status.abs_frame,
163 status.total_min, status.total_sec, status.total_frame,
164 status.first, status.last, status.scsi_audio,
165 status.cur_block, status.polyfilla[0],
166 status.polyfilla[1], status.polyfilla[2]);
169 static object *
170 CD_gettrackinfo(self, args)
171 cdplayerobject *self;
172 object *args;
174 int track;
175 CDTRACKINFO info;
176 CDSTATUS status;
178 CheckPlayer(self);
180 if (!getargs(args, "i", &track))
181 return NULL;
183 if (!CDgettrackinfo(self->ob_cdplayer, track, &info)) {
184 if (CDgetstatus(self->ob_cdplayer, &status) &&
185 status.state == CD_NODISC)
186 err_setstr(CdError, "no disc in player");
187 else
188 err_setstr(CdError, "gettrackinfo failed");
189 return NULL;
192 return mkvalue("((iii)(iii))",
193 info.start_min, info.start_sec, info.start_frame,
194 info.total_min, info.total_sec, info.total_frame);
197 static object *
198 CD_msftoblock(self, args)
199 cdplayerobject *self;
200 object *args;
202 int min, sec, frame;
203 unsigned long block;
205 CheckPlayer(self);
207 if (!getargs(args, "(iii)", &min, &sec, &frame))
208 return NULL;
210 block = CDmsftoblock(self->ob_cdplayer, min, sec, frame);
211 return newintobject((long) block);
214 static object *
215 CD_play(self, args)
216 cdplayerobject *self;
217 object *args;
219 int start, play;
220 CDSTATUS status;
222 CheckPlayer(self);
224 if (!getargs(args, "(ii)", &start, &play))
225 return NULL;
227 if (!CDplay(self->ob_cdplayer, start, play)) {
228 if (CDgetstatus(self->ob_cdplayer, &status) &&
229 status.state == CD_NODISC)
230 err_setstr(CdError, "no disc in player");
231 else
232 err_setstr(CdError, "play failed");
233 return NULL;
236 INCREF(None);
237 return None;
240 static object *
241 CD_playabs(self, args)
242 cdplayerobject *self;
243 object *args;
245 int min, sec, frame, play;
246 CDSTATUS status;
248 CheckPlayer(self);
250 if (!getargs(args, "(iiii)", &min, &sec, &frame, &play))
251 return NULL;
253 if (!CDplayabs(self->ob_cdplayer, min, sec, frame, play)) {
254 if (CDgetstatus(self->ob_cdplayer, &status) &&
255 status.state == CD_NODISC)
256 err_setstr(CdError, "no disc in player");
257 else
258 err_setstr(CdError, "playabs failed");
259 return NULL;
262 INCREF(None);
263 return None;
266 static object *
267 CD_playtrack(self, args)
268 cdplayerobject *self;
269 object *args;
271 int start, play;
272 CDSTATUS status;
274 CheckPlayer(self);
276 if (!getargs(args, "(ii)", &start, &play))
277 return NULL;
279 if (!CDplaytrack(self->ob_cdplayer, start, play)) {
280 if (CDgetstatus(self->ob_cdplayer, &status) &&
281 status.state == CD_NODISC)
282 err_setstr(CdError, "no disc in player");
283 else
284 err_setstr(CdError, "playtrack failed");
285 return NULL;
288 INCREF(None);
289 return None;
292 static object *
293 CD_playtrackabs(self, args)
294 cdplayerobject *self;
295 object *args;
297 int track, min, sec, frame, play;
298 CDSTATUS status;
300 CheckPlayer(self);
302 if (!getargs(args, "(iiiii)", &track, &min, &sec, &frame, &play))
303 return NULL;
305 if (!CDplaytrackabs(self->ob_cdplayer, track, min, sec, frame, play)) {
306 if (CDgetstatus(self->ob_cdplayer, &status) &&
307 status.state == CD_NODISC)
308 err_setstr(CdError, "no disc in player");
309 else
310 err_setstr(CdError, "playtrackabs failed");
311 return NULL;
314 INCREF(None);
315 return None;
318 static object *
319 CD_readda(self, args)
320 cdplayerobject *self;
321 object *args;
323 int numframes, n;
324 object *result;
326 CheckPlayer(self);
328 if (!getargs(args, "i", &numframes))
329 return NULL;
331 result = newsizedstringobject(NULL, numframes * sizeof(CDFRAME));
332 if (result == NULL)
333 return NULL;
335 n = CDreadda(self->ob_cdplayer, (CDFRAME *) getstringvalue(result), numframes);
336 if (n == -1) {
337 DECREF(result);
338 err_errno(CdError);
339 return NULL;
341 if (n < numframes)
342 if (resizestring(&result, n * sizeof(CDFRAME)))
343 return NULL;
345 return result;
348 static object *
349 CD_seek(self, args)
350 cdplayerobject *self;
351 object *args;
353 int min, sec, frame;
354 long block;
356 CheckPlayer(self);
358 if (!getargs(args, "(iii)", &min, &sec, &frame))
359 return NULL;
361 block = CDseek(self->ob_cdplayer, min, sec, frame);
362 if (block == -1) {
363 err_errno(CdError);
364 return NULL;
367 return newintobject(block);
370 static object *
371 CD_seektrack(self, args)
372 cdplayerobject *self;
373 object *args;
375 int track;
376 long block;
378 CheckPlayer(self);
380 if (!getargs(args, "i", &track))
381 return NULL;
383 block = CDseektrack(self->ob_cdplayer, track);
384 if (block == -1) {
385 err_errno(CdError);
386 return NULL;
389 return newintobject(block);
392 static object *
393 CD_stop(self, args)
394 cdplayerobject *self;
395 object *args;
397 CDSTATUS status;
399 CheckPlayer(self);
401 if (!getnoarg(args))
402 return NULL;
404 if (!CDstop(self->ob_cdplayer)) {
405 if (CDgetstatus(self->ob_cdplayer, &status) &&
406 status.state == CD_NODISC)
407 err_setstr(CdError, "no disc in player");
408 else
409 err_setstr(CdError, "stop failed");
410 return NULL;
413 INCREF(None);
414 return None;
417 static object *
418 CD_togglepause(self, args)
419 cdplayerobject *self;
420 object *args;
422 CDSTATUS status;
424 CheckPlayer(self);
426 if (!getnoarg(args))
427 return NULL;
429 if (!CDtogglepause(self->ob_cdplayer)) {
430 if (CDgetstatus(self->ob_cdplayer, &status) &&
431 status.state == CD_NODISC)
432 err_setstr(CdError, "no disc in player");
433 else
434 err_setstr(CdError, "togglepause failed");
435 return NULL;
438 INCREF(None);
439 return None;
442 static struct methodlist cdplayer_methods[] = {
443 {"allowremoval", (method)CD_allowremoval},
444 {"bestreadsize", (method)CD_bestreadsize},
445 {"close", (method)CD_close},
446 {"eject", (method)CD_eject},
447 {"getstatus", (method)CD_getstatus},
448 {"gettrackinfo", (method)CD_gettrackinfo},
449 {"msftoblock", (method)CD_msftoblock},
450 {"play", (method)CD_play},
451 {"playabs", (method)CD_playabs},
452 {"playtrack", (method)CD_playtrack},
453 {"playtrackabs", (method)CD_playtrackabs},
454 {"preventremoval", (method)CD_preventremoval},
455 {"readda", (method)CD_readda},
456 {"seek", (method)CD_seek},
457 {"seektrack", (method)CD_seektrack},
458 {"stop", (method)CD_stop},
459 {"togglepause", (method)CD_togglepause},
460 {NULL, NULL} /* sentinel */
463 static void
464 cdplayer_dealloc(self)
465 cdplayerobject *self;
467 if (self->ob_cdplayer != NULL)
468 CDclose(self->ob_cdplayer);
469 DEL(self);
472 static object *
473 cdplayer_getattr(cdp, name)
474 cdplayerobject *cdp;
475 char *name;
477 return findmethod(cdplayer_methods, (object *)cdp, name);
480 typeobject CdPlayertype = {
481 OB_HEAD_INIT(&Typetype)
482 0, /*ob_size*/
483 "cdplayer", /*tp_name*/
484 sizeof(cdplayerobject), /*tp_size*/
485 0, /*tp_itemsize*/
486 /* methods */
487 (destructor)cdplayer_dealloc, /*tp_dealloc*/
488 0, /*tp_print*/
489 (getattrfunc)cdplayer_getattr, /*tp_getattr*/
490 0, /*tp_setattr*/
491 0, /*tp_compare*/
492 0, /*tp_repr*/
495 static object *
496 newcdplayerobject(cdp)
497 CDPLAYER *cdp;
499 cdplayerobject *p;
501 p = NEWOBJ(cdplayerobject, &CdPlayertype);
502 if (p == NULL)
503 return NULL;
504 p->ob_cdplayer = cdp;
505 return (object *) p;
508 static object *
509 CD_open(self, args)
510 object *self, *args;
512 char *dev, *direction;
513 CDPLAYER *cdp;
516 * Variable number of args.
517 * First defaults to "None", second defaults to "r".
519 dev = NULL;
520 direction = "r";
521 if (!getnoarg(args)) {
522 err_clear();
523 if (!getargs(args, "z", &dev)) {
524 err_clear();
525 if (!getargs(args, "(zs)", &dev, &direction))
526 return NULL;
530 cdp = CDopen(dev, direction);
531 if (cdp == NULL) {
532 err_errno(CdError);
533 return NULL;
536 return newcdplayerobject(cdp);
539 typedef struct {
540 OB_HEAD
541 CDPARSER *ob_cdparser;
542 struct {
543 object *ob_cdcallback;
544 object *ob_cdcallbackarg;
545 } ob_cdcallbacks[NCALLBACKS];
546 } cdparserobject;
548 static void
549 CD_callback(arg, type, data)
550 void *arg;
551 CDDATATYPES type;
552 void *data;
554 object *result, *args, *v;
555 char *p;
556 int i;
557 cdparserobject *self;
559 self = (cdparserobject *) arg;
560 args = newtupleobject(3);
561 if (args == NULL)
562 return;
563 INCREF(self->ob_cdcallbacks[type].ob_cdcallbackarg);
564 settupleitem(args, 0, self->ob_cdcallbacks[type].ob_cdcallbackarg);
565 settupleitem(args, 1, newintobject((long) type));
566 switch (type) {
567 case cd_audio:
568 v = newsizedstringobject(data, CDDA_DATASIZE);
569 break;
570 case cd_pnum:
571 case cd_index:
572 v = newintobject(((CDPROGNUM *) data)->value);
573 break;
574 case cd_ptime:
575 case cd_atime:
576 #define ptr ((struct cdtimecode *) data)
577 v = mkvalue("(iii)", ptr->mhi * 10 + ptr->mlo,
578 ptr->shi * 10 + ptr->slo,
579 ptr->fhi * 10 + ptr->flo);
580 #undef ptr
581 break;
582 case cd_catalog:
583 v = newsizedstringobject(NULL, 13);
584 p = getstringvalue(v);
585 for (i = 0; i < 13; i++)
586 *p++ = ((char *) data)[i] + '0';
587 break;
588 case cd_ident:
589 v = newsizedstringobject(NULL, 12);
590 p = getstringvalue(v);
591 CDsbtoa(p, ((struct cdident *) data)->country, 2);
592 p += 2;
593 CDsbtoa(p, ((struct cdident *) data)->owner, 3);
594 p += 3;
595 *p++ = ((struct cdident *) data)->year[0] + '0';
596 *p++ = ((struct cdident *) data)->year[1] + '0';
597 *p++ = ((struct cdident *) data)->serial[0] + '0';
598 *p++ = ((struct cdident *) data)->serial[1] + '0';
599 *p++ = ((struct cdident *) data)->serial[2] + '0';
600 *p++ = ((struct cdident *) data)->serial[3] + '0';
601 *p++ = ((struct cdident *) data)->serial[4] + '0';
602 break;
603 case cd_control:
604 v = newintobject((long) *((unchar *) data));
605 break;
607 settupleitem(args, 2, v);
608 if (err_occurred()) {
609 DECREF(args);
610 return;
613 result = call_object(self->ob_cdcallbacks[type].ob_cdcallback, args);
614 DECREF(args);
615 XDECREF(result);
618 static object *
619 CD_deleteparser(self, args)
620 cdparserobject *self;
621 object *args;
623 int i;
625 CheckParser(self);
627 if (!getnoarg(args))
628 return NULL;
630 CDdeleteparser(self->ob_cdparser);
631 self->ob_cdparser = NULL;
633 /* no sense in keeping the callbacks, so remove them */
634 for (i = 0; i < NCALLBACKS; i++) {
635 XDECREF(self->ob_cdcallbacks[i].ob_cdcallback);
636 self->ob_cdcallbacks[i].ob_cdcallback = NULL;
637 XDECREF(self->ob_cdcallbacks[i].ob_cdcallbackarg);
638 self->ob_cdcallbacks[i].ob_cdcallbackarg = NULL;
641 INCREF(None);
642 return None;
645 static object *
646 CD_parseframe(self, args)
647 cdparserobject *self;
648 object *args;
650 char *cdfp;
651 int length;
652 CDFRAME *p;
654 CheckParser(self);
656 if (!getargs(args, "s#", &cdfp, &length))
657 return NULL;
659 if (length % sizeof(CDFRAME) != 0) {
660 err_setstr(TypeError, "bad length");
661 return NULL;
664 p = (CDFRAME *) cdfp;
665 while (length > 0) {
666 CDparseframe(self->ob_cdparser, p);
667 length -= sizeof(CDFRAME);
668 p++;
669 if (err_occurred())
670 return NULL;
673 INCREF(None);
674 return None;
677 static object *
678 CD_removecallback(self, args)
679 cdparserobject *self;
680 object *args;
682 int type;
684 CheckParser(self);
686 if (!getargs(args, "i", &type))
687 return NULL;
689 if (type < 0 || type >= NCALLBACKS) {
690 err_setstr(TypeError, "bad type");
691 return NULL;
694 CDremovecallback(self->ob_cdparser, (CDDATATYPES) type);
696 XDECREF(self->ob_cdcallbacks[type].ob_cdcallback);
697 self->ob_cdcallbacks[type].ob_cdcallback = NULL;
699 XDECREF(self->ob_cdcallbacks[type].ob_cdcallbackarg);
700 self->ob_cdcallbacks[type].ob_cdcallbackarg = NULL;
702 INCREF(None);
703 return None;
706 static object *
707 CD_resetparser(self, args)
708 cdparserobject *self;
709 object *args;
711 CheckParser(self);
713 if (!getnoarg(args))
714 return NULL;
716 CDresetparser(self->ob_cdparser);
718 INCREF(None);
719 return None;
722 static object *
723 CD_addcallback(self, args)
724 cdparserobject *self;
725 object *args;
727 int type;
728 object *func, *funcarg;
730 CheckParser(self);
732 /* XXX - more work here */
733 if (!getargs(args, "(iOO)", &type, &func, &funcarg))
734 return NULL;
736 if (type < 0 || type >= NCALLBACKS) {
737 err_setstr(TypeError, "argument out of range");
738 return NULL;
741 #ifdef CDsetcallback
742 CDaddcallback(self->ob_cdparser, (CDDATATYPES) type, CD_callback, (void *) self);
743 #else
744 CDsetcallback(self->ob_cdparser, (CDDATATYPES) type, CD_callback, (void *) self);
745 #endif
746 XDECREF(self->ob_cdcallbacks[type].ob_cdcallback);
747 INCREF(func);
748 self->ob_cdcallbacks[type].ob_cdcallback = func;
749 XDECREF(self->ob_cdcallbacks[type].ob_cdcallbackarg);
750 INCREF(funcarg);
751 self->ob_cdcallbacks[type].ob_cdcallbackarg = funcarg;
753 INCREF(None);
754 return None;
757 static struct methodlist cdparser_methods[] = {
758 {"addcallback", (method)CD_addcallback},
759 {"deleteparser", (method)CD_deleteparser},
760 {"parseframe", (method)CD_parseframe},
761 {"removecallback", (method)CD_removecallback},
762 {"resetparser", (method)CD_resetparser},
763 {"setcallback", (method)CD_addcallback}, /* backward compatibility */
764 {NULL, NULL} /* sentinel */
767 static void
768 cdparser_dealloc(self)
769 cdparserobject *self;
771 int i;
773 for (i = 0; i < NCALLBACKS; i++) {
774 XDECREF(self->ob_cdcallbacks[i].ob_cdcallback);
775 self->ob_cdcallbacks[i].ob_cdcallback = NULL;
776 XDECREF(self->ob_cdcallbacks[i].ob_cdcallbackarg);
777 self->ob_cdcallbacks[i].ob_cdcallbackarg = NULL;
779 CDdeleteparser(self->ob_cdparser);
780 DEL(self);
783 static object *
784 cdparser_getattr(cdp, name)
785 cdparserobject *cdp;
786 char *name;
788 return findmethod(cdparser_methods, (object *)cdp, name);
791 typeobject CdParsertype = {
792 OB_HEAD_INIT(&Typetype)
793 0, /*ob_size*/
794 "cdparser", /*tp_name*/
795 sizeof(cdparserobject), /*tp_size*/
796 0, /*tp_itemsize*/
797 /* methods */
798 (destructor)cdparser_dealloc, /*tp_dealloc*/
799 0, /*tp_print*/
800 (getattrfunc)cdparser_getattr, /*tp_getattr*/
801 0, /*tp_setattr*/
802 0, /*tp_compare*/
803 0, /*tp_repr*/
806 static object *
807 newcdparserobject(cdp)
808 CDPARSER *cdp;
810 cdparserobject *p;
811 int i;
813 p = NEWOBJ(cdparserobject, &CdParsertype);
814 if (p == NULL)
815 return NULL;
816 p->ob_cdparser = cdp;
817 for (i = 0; i < NCALLBACKS; i++) {
818 p->ob_cdcallbacks[i].ob_cdcallback = NULL;
819 p->ob_cdcallbacks[i].ob_cdcallbackarg = NULL;
821 return (object *) p;
824 static object *
825 CD_createparser(self, args)
826 object *self, *args;
828 CDPARSER *cdp;
830 if (!getnoarg(args))
831 return NULL;
832 cdp = CDcreateparser();
833 if (cdp == NULL) {
834 err_setstr(CdError, "createparser failed");
835 return NULL;
838 return newcdparserobject(cdp);
841 static object *
842 CD_sbtoa(self, args)
843 object *self;
844 object *args;
846 char *sb;
847 int length;
848 object *result;
850 if (!getargs(args, "s#", &sb, &length))
851 return NULL;
852 result = newsizedstringobject(NULL, length);
853 CDsbtoa(getstringvalue(result), (unchar *) sb, length);
854 return result;
857 static object *
858 CD_timetoa(self, args)
859 object *self;
860 object *args;
862 char *tc;
863 int length;
864 object *result;
866 if (!getargs(args, "s#", &tc, &length))
867 return NULL;
869 if (length != sizeof(struct cdtimecode)) {
870 err_setstr(TypeError, "bad length");
871 return NULL;
874 result = newsizedstringobject(NULL, 8);
875 CDtimetoa(getstringvalue(result), (struct cdtimecode *) tc);
876 return result;
879 static struct methodlist CD_methods[] = {
880 {"sbtoa", (method)CD_sbtoa},
881 {"open", (method)CD_open},
882 {"createparser",(method)CD_createparser},
883 {"timetoa", (method)CD_timetoa},
884 {NULL, NULL} /* Sentinel */
887 void
888 initcd()
890 object *m, *d;
892 m = initmodule("cd", CD_methods);
893 d = getmoduledict(m);
895 CdError = newstringobject("cd.error");
896 if (CdError == NULL || dictinsert(d, "error", CdError) != 0)
897 fatal("can't define cd.error");