cdmodule.c 18.9 KB
Newer Older
Guido van Rossum's avatar
Guido van Rossum committed
1 2 3 4 5
/* CD module -- interface to Mark Callow's and Roger Chickering's */
 /* CD Audio Library (CD). */

#include <sys/types.h>
#include <cdaudio.h>
6
#include "Python.h"
Guido van Rossum's avatar
Guido van Rossum committed
7 8 9 10

#define NCALLBACKS	8

typedef struct {
11
	PyObject_HEAD
Guido van Rossum's avatar
Guido van Rossum committed
12 13 14
	CDPLAYER *ob_cdplayer;
} cdplayerobject;

15
static PyObject *CdError;		/* exception cd.error */
16

17
static PyObject *
18
CD_allowremoval(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
19
{
20
	if (!PyArg_ParseTuple(args, ":allowremoval"))
Guido van Rossum's avatar
Guido van Rossum committed
21 22 23 24
		return NULL;

	CDallowremoval(self->ob_cdplayer);

25 26
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
27 28
}

29
static PyObject *
30
CD_preventremoval(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
31
{
32
	if (!PyArg_ParseTuple(args, ":preventremoval"))
Guido van Rossum's avatar
Guido van Rossum committed
33 34 35 36
		return NULL;

	CDpreventremoval(self->ob_cdplayer);

37 38
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
39 40
}

41
static PyObject *
42
CD_bestreadsize(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
43
{
44
	if (!PyArg_ParseTuple(args, ":bestreadsize"))
Guido van Rossum's avatar
Guido van Rossum committed
45 46
		return NULL;

47
	return PyInt_FromLong((long) CDbestreadsize(self->ob_cdplayer));
Guido van Rossum's avatar
Guido van Rossum committed
48 49
}

50
static PyObject *
51
CD_close(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
52
{
53
	if (!PyArg_ParseTuple(args, ":close"))
Guido van Rossum's avatar
Guido van Rossum committed
54 55 56
		return NULL;

	if (!CDclose(self->ob_cdplayer)) {
57
		PyErr_SetFromErrno(CdError); /* XXX - ??? */
Guido van Rossum's avatar
Guido van Rossum committed
58 59 60 61
		return NULL;
	}
	self->ob_cdplayer = NULL;

62 63
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
64 65
}

66
static PyObject *
67
CD_eject(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
68
{
69 70
	CDSTATUS status;

71
	if (!PyArg_ParseTuple(args, ":eject"))
Guido van Rossum's avatar
Guido van Rossum committed
72 73 74
		return NULL;

	if (!CDeject(self->ob_cdplayer)) {
75 76
		if (CDgetstatus(self->ob_cdplayer, &status) &&
		    status.state == CD_NODISC)
77
			PyErr_SetString(CdError, "no disc in player");
78
		else
79
			PyErr_SetString(CdError, "eject failed");
Guido van Rossum's avatar
Guido van Rossum committed
80 81 82
		return NULL;
	}

83 84
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
85 86
}
	
87
static PyObject *
88
CD_getstatus(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
89 90 91
{
	CDSTATUS status;

92
	if (!PyArg_ParseTuple(args, ":getstatus"))
Guido van Rossum's avatar
Guido van Rossum committed
93 94 95
		return NULL;

	if (!CDgetstatus(self->ob_cdplayer, &status)) {
96
		PyErr_SetFromErrno(CdError); /* XXX - ??? */
Guido van Rossum's avatar
Guido van Rossum committed
97 98 99
		return NULL;
	}

100
	return Py_BuildValue("(ii(iii)(iii)(iii)iiii)", status.state,
101 102 103 104
		       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,
105
		       status.cur_block);
Guido van Rossum's avatar
Guido van Rossum committed
106 107
}
	
108
static PyObject *
109
CD_gettrackinfo(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
110 111 112
{
	int track;
	CDTRACKINFO info;
113
	CDSTATUS status;
Guido van Rossum's avatar
Guido van Rossum committed
114

115
	if (!PyArg_ParseTuple(args, "i:gettrackinfo", &track))
Guido van Rossum's avatar
Guido van Rossum committed
116 117 118
		return NULL;

	if (!CDgettrackinfo(self->ob_cdplayer, track, &info)) {
119 120
		if (CDgetstatus(self->ob_cdplayer, &status) &&
		    status.state == CD_NODISC)
121
			PyErr_SetString(CdError, "no disc in player");
122
		else
123
			PyErr_SetString(CdError, "gettrackinfo failed");
Guido van Rossum's avatar
Guido van Rossum committed
124 125 126
		return NULL;
	}

127
	return Py_BuildValue("((iii)(iii))",
Guido van Rossum's avatar
Guido van Rossum committed
128 129 130 131
		       info.start_min, info.start_sec, info.start_frame,
		       info.total_min, info.total_sec, info.total_frame);
}
	
132
static PyObject *
133
CD_msftoblock(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
134 135 136
{
	int min, sec, frame;

137
	if (!PyArg_ParseTuple(args, "iii:msftoblock", &min, &sec, &frame))
Guido van Rossum's avatar
Guido van Rossum committed
138 139
		return NULL;

140
	return PyInt_FromLong((long) CDmsftoblock(self->ob_cdplayer,
141
						min, sec, frame));
Guido van Rossum's avatar
Guido van Rossum committed
142 143
}
	
144
static PyObject *
145
CD_play(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
146 147
{
	int start, play;
148
	CDSTATUS status;
Guido van Rossum's avatar
Guido van Rossum committed
149

150
	if (!PyArg_ParseTuple(args, "ii:play", &start, &play))
Guido van Rossum's avatar
Guido van Rossum committed
151 152 153
		return NULL;

	if (!CDplay(self->ob_cdplayer, start, play)) {
154 155
		if (CDgetstatus(self->ob_cdplayer, &status) &&
		    status.state == CD_NODISC)
156
			PyErr_SetString(CdError, "no disc in player");
157
		else
158
			PyErr_SetString(CdError, "play failed");
Guido van Rossum's avatar
Guido van Rossum committed
159 160 161
		return NULL;
	}

162 163
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
164 165
}
	
166
static PyObject *
167
CD_playabs(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
168 169
{
	int min, sec, frame, play;
170
	CDSTATUS status;
Guido van Rossum's avatar
Guido van Rossum committed
171

172
	if (!PyArg_ParseTuple(args, "iiii:playabs", &min, &sec, &frame, &play))
Guido van Rossum's avatar
Guido van Rossum committed
173 174 175
		return NULL;

	if (!CDplayabs(self->ob_cdplayer, min, sec, frame, play)) {
176 177
		if (CDgetstatus(self->ob_cdplayer, &status) &&
		    status.state == CD_NODISC)
178
			PyErr_SetString(CdError, "no disc in player");
179
		else
180
			PyErr_SetString(CdError, "playabs failed");
Guido van Rossum's avatar
Guido van Rossum committed
181 182 183
		return NULL;
	}

184 185
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
186 187
}
	
188
static PyObject *
189
CD_playtrack(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
190 191
{
	int start, play;
192
	CDSTATUS status;
Guido van Rossum's avatar
Guido van Rossum committed
193

194
	if (!PyArg_ParseTuple(args, "ii:playtrack", &start, &play))
Guido van Rossum's avatar
Guido van Rossum committed
195 196 197
		return NULL;

	if (!CDplaytrack(self->ob_cdplayer, start, play)) {
198 199
		if (CDgetstatus(self->ob_cdplayer, &status) &&
		    status.state == CD_NODISC)
200
			PyErr_SetString(CdError, "no disc in player");
201
		else
202
			PyErr_SetString(CdError, "playtrack failed");
Guido van Rossum's avatar
Guido van Rossum committed
203 204 205
		return NULL;
	}

206 207
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
208 209
}
	
210
static PyObject *
211
CD_playtrackabs(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
212 213
{
	int track, min, sec, frame, play;
214
	CDSTATUS status;
Guido van Rossum's avatar
Guido van Rossum committed
215

216
	if (!PyArg_ParseTuple(args, "iiiii:playtrackabs", &track, &min, &sec,
217
			      &frame, &play))
Guido van Rossum's avatar
Guido van Rossum committed
218 219 220
		return NULL;

	if (!CDplaytrackabs(self->ob_cdplayer, track, min, sec, frame, play)) {
221 222
		if (CDgetstatus(self->ob_cdplayer, &status) &&
		    status.state == CD_NODISC)
223
			PyErr_SetString(CdError, "no disc in player");
224
		else
225
			PyErr_SetString(CdError, "playtrackabs failed");
Guido van Rossum's avatar
Guido van Rossum committed
226 227 228
		return NULL;
	}

229 230
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
231 232
}
	
233
static PyObject *
234
CD_readda(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
235 236
{
	int numframes, n;
237
	PyObject *result;
Guido van Rossum's avatar
Guido van Rossum committed
238

239
	if (!PyArg_ParseTuple(args, "i:readda", &numframes))
Guido van Rossum's avatar
Guido van Rossum committed
240 241
		return NULL;

242
	result = PyString_FromStringAndSize(NULL, numframes * sizeof(CDFRAME));
Guido van Rossum's avatar
Guido van Rossum committed
243 244 245
	if (result == NULL)
		return NULL;

246
	n = CDreadda(self->ob_cdplayer,
247
		       (CDFRAME *) PyString_AsString(result), numframes);
Guido van Rossum's avatar
Guido van Rossum committed
248
	if (n == -1) {
249 250
		Py_DECREF(result);
		PyErr_SetFromErrno(CdError);
Guido van Rossum's avatar
Guido van Rossum committed
251 252 253
		return NULL;
	}
	if (n < numframes)
254
		_PyString_Resize(&result, n * sizeof(CDFRAME));
Guido van Rossum's avatar
Guido van Rossum committed
255 256 257 258

	return result;
}

259
static PyObject *
260
CD_seek(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
261 262
{
	int min, sec, frame;
263
	long PyTryBlock;
Guido van Rossum's avatar
Guido van Rossum committed
264

265
	if (!PyArg_ParseTuple(args, "iii:seek", &min, &sec, &frame))
Guido van Rossum's avatar
Guido van Rossum committed
266 267
		return NULL;

268 269 270
	PyTryBlock = CDseek(self->ob_cdplayer, min, sec, frame);
	if (PyTryBlock == -1) {
		PyErr_SetFromErrno(CdError);
Guido van Rossum's avatar
Guido van Rossum committed
271 272 273
		return NULL;
	}

274
	return PyInt_FromLong(PyTryBlock);
Guido van Rossum's avatar
Guido van Rossum committed
275 276
}
	
277
static PyObject *
278
CD_seektrack(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
279 280
{
	int track;
281
	long PyTryBlock;
Guido van Rossum's avatar
Guido van Rossum committed
282

283
	if (!PyArg_ParseTuple(args, "i:seektrack", &track))
Guido van Rossum's avatar
Guido van Rossum committed
284 285
		return NULL;

286 287 288
	PyTryBlock = CDseektrack(self->ob_cdplayer, track);
	if (PyTryBlock == -1) {
		PyErr_SetFromErrno(CdError);
Guido van Rossum's avatar
Guido van Rossum committed
289 290 291
		return NULL;
	}

292
	return PyInt_FromLong(PyTryBlock);
Guido van Rossum's avatar
Guido van Rossum committed
293 294
}
	
295
static PyObject *
296
CD_seekblock(cdplayerobject *self, PyObject *args)
297
{
298
	unsigned long PyTryBlock;
299

300
	if (!PyArg_ParseTuple(args, "l:seekblock", &PyTryBlock))
301 302
		return NULL;

303 304 305
	PyTryBlock = CDseekblock(self->ob_cdplayer, PyTryBlock);
	if (PyTryBlock == (unsigned long) -1) {
		PyErr_SetFromErrno(CdError);
306 307 308
		return NULL;
	}

309
	return PyInt_FromLong(PyTryBlock);
310 311
}
	
312
static PyObject *
313
CD_stop(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
314
{
315 316
	CDSTATUS status;

317
	if (!PyArg_ParseTuple(args, ":stop"))
Guido van Rossum's avatar
Guido van Rossum committed
318 319 320
		return NULL;

	if (!CDstop(self->ob_cdplayer)) {
321 322
		if (CDgetstatus(self->ob_cdplayer, &status) &&
		    status.state == CD_NODISC)
323
			PyErr_SetString(CdError, "no disc in player");
324
		else
325
			PyErr_SetString(CdError, "stop failed");
Guido van Rossum's avatar
Guido van Rossum committed
326 327 328
		return NULL;
	}

329 330
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
331 332
}
	
333
static PyObject *
334
CD_togglepause(cdplayerobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
335
{
336 337
	CDSTATUS status;

338
	if (!PyArg_ParseTuple(args, ":togglepause"))
Guido van Rossum's avatar
Guido van Rossum committed
339 340 341
		return NULL;

	if (!CDtogglepause(self->ob_cdplayer)) {
342 343
		if (CDgetstatus(self->ob_cdplayer, &status) &&
		    status.state == CD_NODISC)
344
			PyErr_SetString(CdError, "no disc in player");
345
		else
346
			PyErr_SetString(CdError, "togglepause failed");
Guido van Rossum's avatar
Guido van Rossum committed
347 348 349
		return NULL;
	}

350 351
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
352 353
}
	
354
static PyMethodDef cdplayer_methods[] = {
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
	{"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},
Guido van Rossum's avatar
Guido van Rossum committed
373 374 375 376
	{NULL,			NULL} 		/* sentinel */
};

static void
377
cdplayer_dealloc(cdplayerobject *self)
Guido van Rossum's avatar
Guido van Rossum committed
378 379 380
{
	if (self->ob_cdplayer != NULL)
		CDclose(self->ob_cdplayer);
381
	PyObject_Del(self);
Guido van Rossum's avatar
Guido van Rossum committed
382 383
}

384
static PyObject *
385
cdplayer_getattr(cdplayerobject *self, char *name)
Guido van Rossum's avatar
Guido van Rossum committed
386
{
387
	if (self->ob_cdplayer == NULL) {
388
		PyErr_SetString(PyExc_RuntimeError, "no player active");
389 390
		return NULL;
	}
391
	return Py_FindMethod(cdplayer_methods, (PyObject *)self, name);
Guido van Rossum's avatar
Guido van Rossum committed
392 393
}

394 395
PyTypeObject CdPlayertype = {
	PyObject_HEAD_INIT(&PyType_Type)
Guido van Rossum's avatar
Guido van Rossum committed
396
	0,			/*ob_size*/
397
	"cd.cdplayer",	/*tp_name*/
Guido van Rossum's avatar
Guido van Rossum committed
398 399 400
	sizeof(cdplayerobject),	/*tp_size*/
	0,			/*tp_itemsize*/
	/* methods */
401
	(destructor)cdplayer_dealloc, /*tp_dealloc*/
Guido van Rossum's avatar
Guido van Rossum committed
402
	0,			/*tp_print*/
403
	(getattrfunc)cdplayer_getattr, /*tp_getattr*/
Guido van Rossum's avatar
Guido van Rossum committed
404 405 406 407 408
	0,			/*tp_setattr*/
	0,			/*tp_compare*/
	0,			/*tp_repr*/
};

409
static PyObject *
410
newcdplayerobject(CDPLAYER *cdp)
Guido van Rossum's avatar
Guido van Rossum committed
411 412 413
{
	cdplayerobject *p;

414
	p = PyObject_New(cdplayerobject, &CdPlayertype);
Guido van Rossum's avatar
Guido van Rossum committed
415 416 417
	if (p == NULL)
		return NULL;
	p->ob_cdplayer = cdp;
418
	return (PyObject *) p;
Guido van Rossum's avatar
Guido van Rossum committed
419 420
}

421
static PyObject *
422
CD_open(PyObject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
423 424 425 426 427 428 429 430 431 432
{
	char *dev, *direction;
	CDPLAYER *cdp;

	/*
	 * Variable number of args.
	 * First defaults to "None", second defaults to "r".
	 */
	dev = NULL;
	direction = "r";
433
	if (!PyArg_ParseTuple(args, "|zs:open", &dev, &direction))
434
		return NULL;
Guido van Rossum's avatar
Guido van Rossum committed
435 436 437

	cdp = CDopen(dev, direction);
	if (cdp == NULL) {
438
		PyErr_SetFromErrno(CdError);
Guido van Rossum's avatar
Guido van Rossum committed
439 440 441 442 443 444 445
		return NULL;
	}

	return newcdplayerobject(cdp);
}

typedef struct {
446
	PyObject_HEAD
Guido van Rossum's avatar
Guido van Rossum committed
447 448
	CDPARSER *ob_cdparser;
	struct {
449 450
		PyObject *ob_cdcallback;
		PyObject *ob_cdcallbackarg;
Guido van Rossum's avatar
Guido van Rossum committed
451 452 453 454
	} ob_cdcallbacks[NCALLBACKS];
} cdparserobject;

static void
455
CD_callback(void *arg, CDDATATYPES type, void *data)
Guido van Rossum's avatar
Guido van Rossum committed
456
{
457
	PyObject *result, *args, *v = NULL;
Guido van Rossum's avatar
Guido van Rossum committed
458 459 460 461 462
	char *p;
	int i;
	cdparserobject *self;

	self = (cdparserobject *) arg;
463
	args = PyTuple_New(3);
Guido van Rossum's avatar
Guido van Rossum committed
464 465
	if (args == NULL)
		return;
466 467 468
	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));
Guido van Rossum's avatar
Guido van Rossum committed
469 470
	switch (type) {
	case cd_audio:
471
		v = PyString_FromStringAndSize(data, CDDA_DATASIZE);
Guido van Rossum's avatar
Guido van Rossum committed
472 473 474
		break;
	case cd_pnum:
	case cd_index:
475
		v = PyInt_FromLong(((CDPROGNUM *) data)->value);
Guido van Rossum's avatar
Guido van Rossum committed
476 477 478
		break;
	case cd_ptime:
	case cd_atime:
479
#define ptr ((struct cdtimecode *) data)
480
		v = Py_BuildValue("(iii)",
481
			    ptr->mhi * 10 + ptr->mlo,
482 483 484
			    ptr->shi * 10 + ptr->slo,
			    ptr->fhi * 10 + ptr->flo);
#undef ptr
Guido van Rossum's avatar
Guido van Rossum committed
485 486
		break;
	case cd_catalog:
487 488
		v = PyString_FromStringAndSize(NULL, 13);
		p = PyString_AsString(v);
Guido van Rossum's avatar
Guido van Rossum committed
489 490 491 492
		for (i = 0; i < 13; i++)
			*p++ = ((char *) data)[i] + '0';
		break;
	case cd_ident:
493
#define ptr ((struct cdident *) data)
494 495
		v = PyString_FromStringAndSize(NULL, 12);
		p = PyString_AsString(v);
496
		CDsbtoa(p, ptr->country, 2);
Guido van Rossum's avatar
Guido van Rossum committed
497
		p += 2;
498
		CDsbtoa(p, ptr->owner, 3);
Guido van Rossum's avatar
Guido van Rossum committed
499
		p += 3;
500 501 502 503 504 505 506 507
		*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
Guido van Rossum's avatar
Guido van Rossum committed
508 509
		break;
	case cd_control:
510
		v = PyInt_FromLong((long) *((unchar *) data));
Guido van Rossum's avatar
Guido van Rossum committed
511 512
		break;
	}
513 514 515
	PyTuple_SetItem(args, 2, v);
	if (PyErr_Occurred()) {
		Py_DECREF(args);
Guido van Rossum's avatar
Guido van Rossum committed
516 517 518
		return;
	}
	
519 520 521 522
	result = PyEval_CallObject(self->ob_cdcallbacks[type].ob_cdcallback,
				   args);
	Py_DECREF(args);
	Py_XDECREF(result);
Guido van Rossum's avatar
Guido van Rossum committed
523 524
}

525
static PyObject *
526
CD_deleteparser(cdparserobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
527 528 529
{
	int i;

530
	if (!PyArg_ParseTuple(args, ":deleteparser"))
Guido van Rossum's avatar
Guido van Rossum committed
531 532 533 534 535 536 537
		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++) {
538
		Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallback);
Guido van Rossum's avatar
Guido van Rossum committed
539
		self->ob_cdcallbacks[i].ob_cdcallback = NULL;
540
		Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallbackarg);
Guido van Rossum's avatar
Guido van Rossum committed
541 542 543
		self->ob_cdcallbacks[i].ob_cdcallbackarg = NULL;
	}

544 545
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
546 547
}

548
static PyObject *
549
CD_parseframe(cdparserobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
550 551 552 553 554
{
	char *cdfp;
	int length;
	CDFRAME *p;

555
	if (!PyArg_ParseTuple(args, "s#:parseframe", &cdfp, &length))
Guido van Rossum's avatar
Guido van Rossum committed
556 557 558
		return NULL;

	if (length % sizeof(CDFRAME) != 0) {
559
		PyErr_SetString(PyExc_TypeError, "bad length");
Guido van Rossum's avatar
Guido van Rossum committed
560 561 562 563 564 565 566 567
		return NULL;
	}

	p = (CDFRAME *) cdfp;
	while (length > 0) {
		CDparseframe(self->ob_cdparser, p);
		length -= sizeof(CDFRAME);
		p++;
568
		if (PyErr_Occurred())
Guido van Rossum's avatar
Guido van Rossum committed
569 570 571
			return NULL;
	}

572 573
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
574 575
}

576
static PyObject *
577
CD_removecallback(cdparserobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
578 579 580
{
	int type;

581
	if (!PyArg_ParseTuple(args, "i:removecallback", &type))
Guido van Rossum's avatar
Guido van Rossum committed
582 583
		return NULL;

584
	if (type < 0 || type >= NCALLBACKS) {
585
		PyErr_SetString(PyExc_TypeError, "bad type");
586 587 588
		return NULL;
	}

Guido van Rossum's avatar
Guido van Rossum committed
589 590
	CDremovecallback(self->ob_cdparser, (CDDATATYPES) type);

591
	Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallback);
Guido van Rossum's avatar
Guido van Rossum committed
592 593
	self->ob_cdcallbacks[type].ob_cdcallback = NULL;

594
	Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallbackarg);
Guido van Rossum's avatar
Guido van Rossum committed
595 596
	self->ob_cdcallbacks[type].ob_cdcallbackarg = NULL;

597 598
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
599 600
}

601
static PyObject *
602
CD_resetparser(cdparserobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
603
{
604
	if (!PyArg_ParseTuple(args, ":resetparser"))
Guido van Rossum's avatar
Guido van Rossum committed
605 606 607 608
		return NULL;

	CDresetparser(self->ob_cdparser);

609 610
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
611 612
}

613
static PyObject *
614
CD_addcallback(cdparserobject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
615 616
{
	int type;
617
	PyObject *func, *funcarg;
Guido van Rossum's avatar
Guido van Rossum committed
618 619

	/* XXX - more work here */
620
	if (!PyArg_ParseTuple(args, "iOO:addcallback", &type, &func, &funcarg))
Guido van Rossum's avatar
Guido van Rossum committed
621 622 623
		return NULL;

	if (type < 0 || type >= NCALLBACKS) {
624
		PyErr_SetString(PyExc_TypeError, "argument out of range");
Guido van Rossum's avatar
Guido van Rossum committed
625 626 627
		return NULL;
	}

628
#ifdef CDsetcallback
629 630
	CDaddcallback(self->ob_cdparser, (CDDATATYPES) type, CD_callback,
		      (void *) self);
631
#else
632 633
	CDsetcallback(self->ob_cdparser, (CDDATATYPES) type, CD_callback,
		      (void *) self);
634
#endif
635 636
	Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallback);
	Py_INCREF(func);
637
	self->ob_cdcallbacks[type].ob_cdcallback = func;
638 639
	Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallbackarg);
	Py_INCREF(funcarg);
640
	self->ob_cdcallbacks[type].ob_cdcallbackarg = funcarg;
Guido van Rossum's avatar
Guido van Rossum committed
641

642 643 644
/*
	if (type == cd_audio) {
		sigfpe_[_UNDERFL].repls = _ZERO;
645 646
		handle_sigfpes(_ON, _EN_UNDERFL, NULL,
		                        _ABORT_ON_ERROR, NULL);
647 648 649
	}
*/

650 651
	Py_INCREF(Py_None);
	return Py_None;
Guido van Rossum's avatar
Guido van Rossum committed
652 653
}

654
static PyMethodDef cdparser_methods[] = {
655 656 657 658 659
	{"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},
660
		                                /* backward compatibility */
661
	{"setcallback",		(PyCFunction)CD_addcallback,   	METH_VARARGS},
Guido van Rossum's avatar
Guido van Rossum committed
662 663 664 665
	{NULL,			NULL} 		/* sentinel */
};

static void
666
cdparser_dealloc(cdparserobject *self)
Guido van Rossum's avatar
Guido van Rossum committed
667 668 669 670
{
	int i;

	for (i = 0; i < NCALLBACKS; i++) {
671
		Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallback);
Guido van Rossum's avatar
Guido van Rossum committed
672
		self->ob_cdcallbacks[i].ob_cdcallback = NULL;
673
		Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallbackarg);
Guido van Rossum's avatar
Guido van Rossum committed
674 675 676
		self->ob_cdcallbacks[i].ob_cdcallbackarg = NULL;
	}
	CDdeleteparser(self->ob_cdparser);
677
	PyObject_Del(self);
Guido van Rossum's avatar
Guido van Rossum committed
678 679
}

680
static PyObject *
681
cdparser_getattr(cdparserobject *self, char *name)
Guido van Rossum's avatar
Guido van Rossum committed
682
{
683
	if (self->ob_cdparser == NULL) {
684
		PyErr_SetString(PyExc_RuntimeError, "no parser active");
685 686 687
		return NULL;
	}

688
	return Py_FindMethod(cdparser_methods, (PyObject *)self, name);
Guido van Rossum's avatar
Guido van Rossum committed
689 690
}

691 692
PyTypeObject CdParsertype = {
	PyObject_HEAD_INIT(&PyType_Type)
Guido van Rossum's avatar
Guido van Rossum committed
693
	0,			/*ob_size*/
694
	"cd.cdparser",		/*tp_name*/
Guido van Rossum's avatar
Guido van Rossum committed
695 696 697
	sizeof(cdparserobject),	/*tp_size*/
	0,			/*tp_itemsize*/
	/* methods */
698
	(destructor)cdparser_dealloc, /*tp_dealloc*/
Guido van Rossum's avatar
Guido van Rossum committed
699
	0,			/*tp_print*/
700
	(getattrfunc)cdparser_getattr, /*tp_getattr*/
Guido van Rossum's avatar
Guido van Rossum committed
701 702 703 704 705
	0,			/*tp_setattr*/
	0,			/*tp_compare*/
	0,			/*tp_repr*/
};

706
static PyObject *
707
newcdparserobject(CDPARSER *cdp)
Guido van Rossum's avatar
Guido van Rossum committed
708 709 710 711
{
	cdparserobject *p;
	int i;

712
	p = PyObject_New(cdparserobject, &CdParsertype);
Guido van Rossum's avatar
Guido van Rossum committed
713 714 715 716 717 718 719
	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;
	}
720
	return (PyObject *) p;
Guido van Rossum's avatar
Guido van Rossum committed
721 722
}

723
static PyObject *
724
CD_createparser(PyObject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
725 726 727
{
	CDPARSER *cdp;

728
	if (!PyArg_ParseTuple(args, ":createparser"))
Guido van Rossum's avatar
Guido van Rossum committed
729 730 731
		return NULL;
	cdp = CDcreateparser();
	if (cdp == NULL) {
732
		PyErr_SetString(CdError, "createparser failed");
Guido van Rossum's avatar
Guido van Rossum committed
733 734 735 736 737 738
		return NULL;
	}

	return newcdparserobject(cdp);
}

739
static PyObject *
740
CD_msftoframe(PyObject *self, PyObject *args)
Guido van Rossum's avatar
Guido van Rossum committed
741
{
742
	int min, sec, frame;
Guido van Rossum's avatar
Guido van Rossum committed
743

744
	if (!PyArg_ParseTuple(args, "iii:msftoframe", &min, &sec, &frame))
Guido van Rossum's avatar
Guido van Rossum committed
745 746
		return NULL;

747
	return PyInt_FromLong((long) CDmsftoframe(min, sec, frame));
Guido van Rossum's avatar
Guido van Rossum committed
748
}
749
	
750
static PyMethodDef CD_methods[] = {
751 752 753
	{"open",		(PyCFunction)CD_open,		METH_VARARGS},
	{"createparser",	(PyCFunction)CD_createparser,	METH_VARARGS},
	{"msftoframe",		(PyCFunction)CD_msftoframe,	METH_VARARGS},
Guido van Rossum's avatar
Guido van Rossum committed
754 755 756 757
	{NULL,		NULL}	/* Sentinel */
};

void
758
initcd(void)
Guido van Rossum's avatar
Guido van Rossum committed
759
{
760
	PyObject *m, *d;
761 762 763 764
	
	if (PyErr_WarnPy3k("the cd module has been removed in "
	                   "Python 3.0", 2) < 0)
	    return;
765

766
	m = Py_InitModule("cd", CD_methods);
767 768
	if (m == NULL)
		return;
769
	d = PyModule_GetDict(m);
770

Guido van Rossum's avatar
Guido van Rossum committed
771
	CdError = PyErr_NewException("cd.error", NULL, NULL);
772
	PyDict_SetItemString(d, "error", CdError);
773 774

	/* Identifiers for the different types of callbacks from the parser */
775 776 777 778 779 780 781 782
	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));
783 784

	/* Block size information for digital audio data */
785 786 787 788
	PyDict_SetItemString(d, "DATASIZE",
			   PyInt_FromLong((long) CDDA_DATASIZE));
	PyDict_SetItemString(d, "BLOCKSIZE",
			   PyInt_FromLong((long) CDDA_BLOCKSIZE));
789 790

	/* Possible states for the cd player */
791 792 793 794 795 796
	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));
797
#ifdef CD_CDROM			/* only newer versions of the library */
798
	PyDict_SetItemString(d, "CDROM", PyInt_FromLong((long) CD_CDROM));
799
#endif
Guido van Rossum's avatar
Guido van Rossum committed
800
}