summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Modules/cdmodule.c889
1 files changed, 889 insertions, 0 deletions
diff --git a/Modules/cdmodule.c b/Modules/cdmodule.c
new file mode 100644
index 0000000..d749ada
--- /dev/null
+++ b/Modules/cdmodule.c
@@ -0,0 +1,889 @@
+/**********************************************************
+Copyright 1991, 1992 by Stichting Mathematisch Centrum, Amsterdam, The
+Netherlands.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+******************************************************************/
+
+/* CD module -- interface to Mark Callow's and Roger Chickering's */
+ /* CD Audio Library (CD). */
+
+#include <sys/types.h>
+#include <cdaudio.h>
+#include "allobjects.h"
+#include "import.h"
+#include "modsupport.h"
+#include "compile.h"
+#include "ceval.h"
+
+#define NCALLBACKS 8
+
+typedef struct {
+ OB_HEAD
+ CDPLAYER *ob_cdplayer;
+} cdplayerobject;
+
+#define CheckPlayer(self) if ((self)->ob_cdplayer == NULL) { \
+ err_setstr(RuntimeError, "no player active"); \
+ return NULL; \
+ }
+#define CheckParser(self) if ((self)->ob_cdparser == NULL) { \
+ err_setstr(RuntimeError, "no parser active"); \
+ return NULL; \
+ }
+
+static object *
+CD_allowremoval(self, args)
+ cdplayerobject *self;
+ object *args;
+{
+ CheckPlayer(self);
+
+ if (!getnoarg(args))
+ return NULL;
+
+ CDallowremoval(self->ob_cdplayer);
+
+ INCREF(None);
+ return None;
+}
+
+static object *
+CD_preventremoval(self, args)
+ cdplayerobject *self;
+ object *args;
+{
+ CheckPlayer(self);
+
+ if (!getnoarg(args))
+ return NULL;
+
+ CDpreventremoval(self->ob_cdplayer);
+
+ INCREF(None);
+ return None;
+}
+
+static object *
+CD_getvolume(self, args)
+ cdplayerobject *self;
+ object *args;
+{
+ CDVOLUME vol;
+ int retval;
+
+ CheckPlayer(self);
+
+ if (!getnoarg(args))
+ return NULL;
+
+#if 0
+ if (!CDgetvolume(self->ob_cdplayer, &vol)) {
+ err_setstr(RuntimeError, "getvolume failed");
+ return NULL;
+ }
+#endif
+
+ return mkvalue("(iiiii)", CDgetvolume(self->ob_cdplayer, &vol), \
+ vol.chan0, vol.chan1, vol.chan2, vol.chan3);
+}
+
+static object *
+CD_setvolume(self, args)
+ cdplayerobject *self;
+ object *args;
+{
+ CDVOLUME vol;
+ int retval;
+
+ CheckPlayer(self);
+
+ if (!getargs(args, "(bbbb)", &vol.chan0, &vol.chan1, \
+ &vol.chan2, &vol.chan3))
+ return NULL;
+
+ if (!CDsetvolume(self->ob_cdplayer, &vol)) {
+ err_setstr(RuntimeError, "setvolume failed");
+ return NULL;
+ }
+
+ INCREF(None);
+ return None;
+}
+
+static object *
+CD_bestreadsize(self, args)
+ cdplayerobject *self;
+ object *args;
+{
+ CheckPlayer(self);
+
+ if (!getnoarg(args))
+ return NULL;
+
+ return newintobject((long) CDbestreadsize(self->ob_cdplayer));
+}
+
+static object *
+CD_close(self, args)
+ cdplayerobject *self;
+ object *args;
+{
+ CheckPlayer(self);
+
+ if (!getnoarg(args))
+ return NULL;
+
+ if (!CDclose(self->ob_cdplayer)) {
+ err_errno(RuntimeError); /* XXX - ??? */
+ return NULL;
+ }
+ self->ob_cdplayer = NULL;
+
+ INCREF(None);
+ return None;
+}
+
+static object *
+CD_eject(self, args)
+ cdplayerobject *self;
+ object *args;
+{
+ CheckPlayer(self);
+
+ if (!getnoarg(args))
+ return NULL;
+
+ if (!CDeject(self->ob_cdplayer)) {
+ err_setstr(RuntimeError, "eject failed");
+ return NULL;
+ }
+
+ INCREF(None);
+ return None;
+}
+
+static object *
+CD_getstatus(self, args)
+ cdplayerobject *self;
+ object *args;
+{
+ CDSTATUS status;
+
+ CheckPlayer(self);
+
+ if (!getnoarg(args))
+ return NULL;
+
+ if (!CDgetstatus(self->ob_cdplayer, &status)) {
+ err_errno(RuntimeError); /* XXX - ??? */
+ return NULL;
+ }
+
+ return mkvalue("(iiiiiiiiiiiiiiiiii)", 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,
+ status.polyfilla[0], status.polyfilla[1],
+ status.polyfilla[2]);
+}
+
+static object *
+CD_gettrackinfo(self, args)
+ cdplayerobject *self;
+ object *args;
+{
+ int track;
+ CDTRACKINFO info;
+
+ CheckPlayer(self);
+
+ if (!getargs(args, "i", &track))
+ return NULL;
+
+ if (!CDgettrackinfo(self->ob_cdplayer, track, &info)) {
+ err_setstr(RuntimeError, "gettrackinfo failed");
+ return NULL;
+ }
+
+ return mkvalue("(iiiiii)",
+ info.start_min, info.start_sec, info.start_frame,
+ info.total_min, info.total_sec, info.total_frame);
+}
+
+static object *
+CD_msftoblock(self, args)
+ cdplayerobject *self;
+ object *args;
+{
+ int min, sec, frame;
+ unsigned long block;
+
+ CheckPlayer(self);
+
+ if (!getargs(args, "(iii)", &min, &sec, &frame))
+ return NULL;
+
+ block = CDmsftoblock(self->ob_cdplayer, min, sec, frame);
+ return newintobject((long) block);
+}
+
+static object *
+CD_play(self, args)
+ cdplayerobject *self;
+ object *args;
+{
+ int start, play;
+
+ CheckPlayer(self);
+
+ if (!getargs(args, "(ii)", &start, &play))
+ return NULL;
+
+ if (!CDplay(self->ob_cdplayer, start, play)) {
+ err_setstr(RuntimeError, "play failed");
+ return NULL;
+ }
+
+ INCREF(None);
+ return None;
+}
+
+static object *
+CD_playabs(self, args)
+ cdplayerobject *self;
+ object *args;
+{
+ int min, sec, frame, play;
+
+ CheckPlayer(self);
+
+ if (!getargs(args, "(iiii)", &min, &sec, &frame, &play))
+ return NULL;
+
+ if (!CDplayabs(self->ob_cdplayer, min, sec, frame, play)) {
+ err_setstr(RuntimeError, "playabs failed");
+ return NULL;
+ }
+
+ INCREF(None);
+ return None;
+}
+
+static object *
+CD_playtrack(self, args)
+ cdplayerobject *self;
+ object *args;
+{
+ int start, play;
+
+ CheckPlayer(self);
+
+ if (!getargs(args, "(ii)", &start, &play))
+ return NULL;
+
+ if (!CDplaytrack(self->ob_cdplayer, start, play)) {
+ err_setstr(RuntimeError, "playtrack failed");
+ return NULL;
+ }
+
+ INCREF(None);
+ return None;
+}
+
+static object *
+CD_playtrackabs(self, args)
+ cdplayerobject *self;
+ object *args;
+{
+ int track, min, sec, frame, play;
+
+ CheckPlayer(self);
+
+ if (!getargs(args, "(iiiii)", &track, &min, &sec, &frame, &play))
+ return NULL;
+
+ if (!CDplaytrackabs(self->ob_cdplayer, track, min, sec, frame, play)) {
+ err_setstr(RuntimeError, "playtrackabs failed");
+ return NULL;
+ }
+
+ INCREF(None);
+ return None;
+}
+
+static object *
+CD_readda(self, args)
+ cdplayerobject *self;
+ object *args;
+{
+ int numframes, n;
+ object *result;
+
+ CheckPlayer(self);
+
+ if (!getargs(args, "i", &numframes))
+ return NULL;
+
+ result = newsizedstringobject(NULL, numframes * sizeof(CDFRAME));
+ if (result == NULL)
+ return NULL;
+
+ n = CDreadda(self->ob_cdplayer, (CDFRAME *) getstringvalue(result), numframes);
+ if (n == -1) {
+ DECREF(result);
+ err_errno(RuntimeError); /* XXX - ??? (seems to work) */
+ return NULL;
+ }
+ if (n < numframes)
+ if (resizestring(&result, n * sizeof(CDFRAME)))
+ return NULL;
+
+ return result;
+}
+
+static object *
+CD_seek(self, args)
+ cdplayerobject *self;
+ object *args;
+{
+ int min, sec, frame;
+ long block;
+
+ CheckPlayer(self);
+
+ if (!getargs(args, "(iii)", &min, &sec, &frame))
+ return NULL;
+
+ block = CDseek(self->ob_cdplayer, min, sec, frame);
+ if (block == -1) {
+ err_errno(RuntimeError);
+ return NULL;
+ }
+
+ return newintobject(block);
+}
+
+static object *
+CD_seektrack(self, args)
+ cdplayerobject *self;
+ object *args;
+{
+ int track;
+ long block;
+
+ CheckPlayer(self);
+
+ if (!getargs(args, "i", &track))
+ return NULL;
+
+ block = CDseektrack(self->ob_cdplayer, track);
+ if (block == -1) {
+ err_errno(RuntimeError);
+ return NULL;
+ }
+
+ return newintobject(block);
+}
+
+static object *
+CD_stop(self, args)
+ cdplayerobject *self;
+ object *args;
+{
+ CheckPlayer(self);
+
+ if (!getnoarg(args))
+ return NULL;
+
+ if (!CDstop(self->ob_cdplayer)) {
+ err_setstr(RuntimeError, "stop failed");
+ return NULL;
+ }
+
+ INCREF(None);
+ return None;
+}
+
+static object *
+CD_togglepause(self, args)
+ cdplayerobject *self;
+ object *args;
+{
+ CheckPlayer(self);
+
+ if (!getnoarg(args))
+ return NULL;
+
+ if (!CDtogglepause(self->ob_cdplayer)) {
+ err_setstr(RuntimeError, "togglepause failed");
+ return NULL;
+ }
+
+ INCREF(None);
+ return None;
+}
+
+static struct methodlist cdplayer_methods[] = {
+ {"allowremoval", CD_allowremoval},
+ {"bestreadsize", CD_bestreadsize},
+ {"close", CD_close},
+ {"eject", CD_eject},
+ {"getstatus", CD_getstatus},
+ {"gettrackinfo", CD_gettrackinfo},
+ {"getvolume", CD_getvolume},
+ {"msftoblock", CD_msftoblock},
+ {"play", CD_play},
+ {"playabs", CD_playabs},
+ {"playtrack", CD_playtrack},
+ {"playtrackabs", CD_playtrackabs},
+ {"preventremoval", CD_preventremoval},
+ {"readda", CD_readda},
+ {"seek", CD_seek},
+ {"seektrack", CD_seektrack},
+ {"setvolume", CD_setvolume},
+ {"stop", CD_stop},
+ {"togglepause", CD_togglepause},
+ {NULL, NULL} /* sentinel */
+};
+
+static void
+cdplayer_dealloc(self)
+ cdplayerobject *self;
+{
+ if (self->ob_cdplayer != NULL)
+ CDclose(self->ob_cdplayer);
+ DEL(self);
+}
+
+static object *
+cdplayer_getattr(cdp, name)
+ cdplayerobject *cdp;
+ char *name;
+{
+ return findmethod(cdplayer_methods, (object *)cdp, name);
+}
+
+typeobject CdPlayertype = {
+ OB_HEAD_INIT(&Typetype)
+ 0, /*ob_size*/
+ "cdplayer", /*tp_name*/
+ sizeof(cdplayerobject), /*tp_size*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ cdplayer_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ cdplayer_getattr, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+};
+
+static object *
+newcdplayerobject(cdp)
+ CDPLAYER *cdp;
+{
+ cdplayerobject *p;
+
+ p = NEWOBJ(cdplayerobject, &CdPlayertype);
+ if (p == NULL)
+ return NULL;
+ p->ob_cdplayer = cdp;
+ return (object *) p;
+}
+
+static object *
+CD_open(self, args)
+ object *self, *args;
+{
+ char *dev, *direction;
+ CDPLAYER *cdp;
+
+ /*
+ * Variable number of args.
+ * First defaults to "None", second defaults to "r".
+ */
+ dev = NULL;
+ direction = "r";
+ if (!getnoarg(args)) {
+ err_clear();
+ if (!getargs(args, "z", &dev)) {
+ err_clear();
+ if (!getargs(args, "(zs)", &dev, &direction))
+ return NULL;
+ }
+ }
+
+ cdp = CDopen(dev, direction);
+ if (cdp == NULL) {
+ err_errno(RuntimeError);
+ return NULL;
+ }
+
+ return newcdplayerobject(cdp);
+}
+
+typedef struct {
+ OB_HEAD
+ CDPARSER *ob_cdparser;
+ struct {
+ object *ob_cdcallback;
+ object *ob_cdcallbackarg;
+ } ob_cdcallbacks[NCALLBACKS];
+} cdparserobject;
+
+static void
+CD_callback(arg, type, data)
+ void *arg;
+ CDDATATYPES type;
+ void *data;
+{
+ object *result, *args, *v;
+ char *p;
+ int i;
+ cdparserobject *self;
+
+ self = (cdparserobject *) arg;
+ args = newtupleobject(3);
+ if (args == NULL)
+ return;
+ INCREF(self->ob_cdcallbacks[type].ob_cdcallbackarg);
+ settupleitem(args, 0, self->ob_cdcallbacks[type].ob_cdcallbackarg);
+ settupleitem(args, 1, newintobject((long) type));
+ switch (type) {
+ case cd_audio:
+ v = newsizedstringobject(data, CDDA_DATASIZE);
+ break;
+ case cd_pnum:
+ case cd_index:
+ v = newintobject(((CDPROGNUM *) data)->value);
+ break;
+ case cd_ptime:
+ case cd_atime:
+ v = newsizedstringobject(NULL, 6);
+ p = getstringvalue(v);
+ *p++ = ((struct cdtimecode *) data)->mhi + '0';
+ *p++ = ((struct cdtimecode *) data)->mlo + '0';
+ *p++ = ((struct cdtimecode *) data)->shi + '0';
+ *p++ = ((struct cdtimecode *) data)->slo + '0';
+ *p++ = ((struct cdtimecode *) data)->fhi + '0';
+ *p++ = ((struct cdtimecode *) data)->flo + '0';
+ break;
+ case cd_catalog:
+ v = newsizedstringobject(NULL, 13);
+ p = getstringvalue(v);
+ for (i = 0; i < 13; i++)
+ *p++ = ((char *) data)[i] + '0';
+ break;
+ case cd_ident:
+ v = newsizedstringobject(NULL, 12);
+ p = getstringvalue(v);
+ CDsbtoa(p, ((struct cdident *) data)->country, 2);
+ p += 2;
+ CDsbtoa(p, ((struct cdident *) data)->owner, 3);
+ p += 3;
+ *p++ = ((struct cdident *) data)->year[0] + '0';
+ *p++ = ((struct cdident *) data)->year[1] + '0';
+ *p++ = ((struct cdident *) data)->serial[0] + '0';
+ *p++ = ((struct cdident *) data)->serial[1] + '0';
+ *p++ = ((struct cdident *) data)->serial[2] + '0';
+ *p++ = ((struct cdident *) data)->serial[3] + '0';
+ *p++ = ((struct cdident *) data)->serial[4] + '0';
+ break;
+ case cd_control:
+ v = newintobject((long) *((unchar *) data));
+ break;
+ }
+ settupleitem(args, 2, v);
+ if (err_occurred()) {
+ DECREF(args);
+ return;
+ }
+
+ result = call_object(self->ob_cdcallbacks[type].ob_cdcallback, args);
+ DECREF(args);
+ XDECREF(result);
+}
+
+static object *
+CD_deleteparser(self, args)
+ cdparserobject *self;
+ object *args;
+{
+ int i;
+
+ CheckParser(self);
+
+ if (!getnoarg(args))
+ 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++) {
+ XDECREF(self->ob_cdcallbacks[i].ob_cdcallback);
+ self->ob_cdcallbacks[i].ob_cdcallback = NULL;
+ XDECREF(self->ob_cdcallbacks[i].ob_cdcallbackarg);
+ self->ob_cdcallbacks[i].ob_cdcallbackarg = NULL;
+ }
+
+ INCREF(None);
+ return None;
+}
+
+static object *
+CD_parseframe(self, args)
+ cdparserobject *self;
+ object *args;
+{
+ char *cdfp;
+ int length;
+ CDFRAME *p;
+
+ CheckParser(self);
+
+ if (!getargs(args, "s#", &cdfp, &length))
+ return NULL;
+
+ if (length % sizeof(CDFRAME) != 0) {
+ err_setstr(RuntimeError, "bad length");
+ return NULL;
+ }
+
+ p = (CDFRAME *) cdfp;
+ while (length > 0) {
+ CDparseframe(self->ob_cdparser, p);
+ length -= sizeof(CDFRAME);
+ p++;
+ if (err_occurred())
+ return NULL;
+ }
+
+ INCREF(None);
+ return None;
+}
+
+static object *
+CD_removecallback(self, args)
+ cdparserobject *self;
+ object *args;
+{
+ int type;
+
+ CheckParser(self);
+
+ if (!getargs(args, "i", &type))
+ return NULL;
+
+ CDremovecallback(self->ob_cdparser, (CDDATATYPES) type);
+
+ XDECREF(self->ob_cdcallbacks[type].ob_cdcallback);
+ self->ob_cdcallbacks[type].ob_cdcallback = NULL;
+
+ XDECREF(self->ob_cdcallbacks[type].ob_cdcallbackarg);
+ self->ob_cdcallbacks[type].ob_cdcallbackarg = NULL;
+
+ INCREF(None);
+ return None;
+}
+
+static object *
+CD_resetparser(self, args)
+ cdparserobject *self;
+ object *args;
+{
+ CheckParser(self);
+
+ if (!getnoarg(args))
+ return NULL;
+
+ CDresetparser(self->ob_cdparser);
+
+ INCREF(None);
+ return None;
+}
+
+static object *
+CD_setcallback(self, args)
+ cdparserobject *self;
+ object *args;
+{
+ int type;
+ object *funcobject, *funcargobject;
+
+ CheckParser(self);
+
+ /* XXX - more work here */
+ if (!getargs(args, "(iOO)", &type, &funcobject, &funcargobject))
+ return NULL;
+
+ if (type < 0 || type >= NCALLBACKS) {
+ err_setstr(RuntimeError, "bad type");
+ return NULL;
+ }
+
+ CDsetcallback(self->ob_cdparser, (CDDATATYPES) type, CD_callback, (void *) self);
+ XDECREF(self->ob_cdcallbacks[type].ob_cdcallback);
+ INCREF(funcobject);
+ self->ob_cdcallbacks[type].ob_cdcallback = funcobject;
+ XDECREF(self->ob_cdcallbacks[type].ob_cdcallbackarg);
+ INCREF(funcargobject);
+ self->ob_cdcallbacks[type].ob_cdcallbackarg = funcargobject;
+
+ INCREF(None);
+ return None;
+}
+
+static struct methodlist cdparser_methods[] = {
+ {"deleteparser", CD_deleteparser},
+ {"parseframe", CD_parseframe},
+ {"removecallback", CD_removecallback},
+ {"resetparser", CD_resetparser},
+ {"setcallback", CD_setcallback},
+ {NULL, NULL} /* sentinel */
+};
+
+static void
+cdparser_dealloc(self)
+ cdparserobject *self;
+{
+ int i;
+
+ for (i = 0; i < NCALLBACKS; i++) {
+ XDECREF(self->ob_cdcallbacks[i].ob_cdcallback);
+ self->ob_cdcallbacks[i].ob_cdcallback = NULL;
+ XDECREF(self->ob_cdcallbacks[i].ob_cdcallbackarg);
+ self->ob_cdcallbacks[i].ob_cdcallbackarg = NULL;
+ }
+ CDdeleteparser(self->ob_cdparser);
+ DEL(self);
+}
+
+static object *
+cdparser_getattr(cdp, name)
+ cdparserobject *cdp;
+ char *name;
+{
+ return findmethod(cdparser_methods, (object *)cdp, name);
+}
+
+typeobject CdParsertype = {
+ OB_HEAD_INIT(&Typetype)
+ 0, /*ob_size*/
+ "cdparser", /*tp_name*/
+ sizeof(cdparserobject), /*tp_size*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ cdparser_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ cdparser_getattr, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ 0, /*tp_repr*/
+};
+
+static object *
+newcdparserobject(cdp)
+ CDPARSER *cdp;
+{
+ cdparserobject *p;
+ int i;
+
+ p = NEWOBJ(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 (object *) p;
+}
+
+static object *
+CD_createparser(self, args)
+ object *self, *args;
+{
+ CDPARSER *cdp;
+
+ if (!getnoarg(args))
+ return NULL;
+ cdp = CDcreateparser();
+ if (cdp == NULL) {
+ err_setstr(RuntimeError, "createparser failed");
+ return NULL;
+ }
+
+ return newcdparserobject(cdp);
+}
+
+static object *
+CD_sbtoa(self, args)
+ object *self;
+ object *args;
+{
+ char *sb;
+ int length;
+ object *result;
+
+ if (!getargs(args, "s#", &sb, &length))
+ return NULL;
+ result = newsizedstringobject(NULL, length);
+ CDsbtoa(getstringvalue(result), (unchar *) sb, length);
+ return result;
+}
+
+static object *
+CD_timetoa(self, args)
+ object *self;
+ object *args;
+{
+ char *tc;
+ int length;
+ object *result;
+
+ if (!getargs(args, "s#", &tc, &length))
+ return NULL;
+
+ if (length != sizeof(struct cdtimecode)) {
+ err_setstr(RuntimeError, "bad length");
+ return NULL;
+ }
+
+ result = newsizedstringobject(NULL, 8);
+ CDtimetoa(getstringvalue(result), (struct cdtimecode *) tc);
+ return result;
+}
+
+static struct methodlist CD_methods[] = {
+ {"sbtoa", CD_sbtoa},
+ {"open", CD_open},
+ {"createparser",CD_createparser},
+ {"timetoa", CD_timetoa},
+ {NULL, NULL} /* Sentinel */
+};
+
+void
+initcd()
+{
+ (void) initmodule("cd", CD_methods);
+}