Initial revision
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);
+}