Annotation of src/usr.bin/cdio/cdio.c, Revision 1.8
1.8 ! downsj 1: /* $OpenBSD: cdio.c,v 1.7 1997/03/19 03:21:49 angelos Exp $ */
1.1 downsj 2: /*
3: * Compact Disc Control Utility by Serge V. Vakulenko <vak@cronyx.ru>.
4: * Based on the non-X based CD player by Jean-Marc Zucconi and
5: * Andrey A. Chernov.
6: *
7: * Fixed and further modified on 5-Sep-1995 by Jukka Ukkonen <jau@funet.fi>.
8: *
9: * 11-Sep-1995: Jukka A. Ukkonen <jau@funet.fi>
10: * A couple of further fixes to my own earlier "fixes".
11: *
12: * 18-Sep-1995: Jukka A. Ukkonen <jau@funet.fi>
13: * Added an ability to specify addresses relative to the
14: * beginning of a track. This is in fact a variation of
15: * doing the simple play_msf() call.
16: *
17: * 11-Oct-1995: Serge V.Vakulenko <vak@cronyx.ru>
18: * New eject algorithm.
19: * Some code style reformatting.
20: *
21: * $FreeBSD: cdcontrol.c,v 1.13 1996/06/25 21:01:27 ache Exp $
22: */
23:
24: #include <ctype.h>
25: #include <stdio.h>
26: #include <stdlib.h>
27: #include <string.h>
28: #include <unistd.h>
29: #include <util.h>
30: #include <errno.h>
31: #include <sys/file.h>
32: #include <sys/cdio.h>
33: #include <sys/ioctl.h>
34:
35: #define VERSION "2.0"
36:
37: #define ASTS_INVALID 0x00 /* Audio status byte not valid */
38: #define ASTS_PLAYING 0x11 /* Audio play operation in progress */
39: #define ASTS_PAUSED 0x12 /* Audio play operation paused */
40: #define ASTS_COMPLETED 0x13 /* Audio play operation successfully completed */
41: #define ASTS_ERROR 0x14 /* Audio play operation stopped due to error */
42: #define ASTS_VOID 0x15 /* No current audio status to return */
43:
44: #ifndef DEFAULT_CD_DRIVE
1.3 deraadt 45: # define DEFAULT_CD_DRIVE "cd0"
1.1 downsj 46: #endif
47:
48: #define CMD_DEBUG 1
49: #define CMD_EJECT 2
50: #define CMD_HELP 3
51: #define CMD_INFO 4
52: #define CMD_PAUSE 5
53: #define CMD_PLAY 6
54: #define CMD_QUIT 7
55: #define CMD_RESUME 8
56: #define CMD_STOP 9
57: #define CMD_VOLUME 10
58: #define CMD_CLOSE 11
59: #define CMD_RESET 12
60: #define CMD_SET 13
61: #define CMD_STATUS 14
1.5 angelos 62: #define CMD_NEXT 15
63: #define CMD_PREV 16
1.6 angelos 64: #define CMD_REPLAY 17
1.1 downsj 65:
66: struct cmdtab {
67: int command;
68: char *name;
69: unsigned min;
70: char *args;
71: } cmdtab[] = {
72: { CMD_CLOSE, "close", 1, "" },
73: { CMD_DEBUG, "debug", 1, "on | off" },
74: { CMD_EJECT, "eject", 1, "" },
75: { CMD_HELP, "?", 1, 0 },
76: { CMD_HELP, "help", 1, "" },
77: { CMD_INFO, "info", 1, "" },
1.5 angelos 78: { CMD_NEXT, "next", 1, "" },
1.1 downsj 79: { CMD_PAUSE, "pause", 2, "" },
80: { CMD_PLAY, "play", 1, "min1:sec1[.fram1] [min2:sec2[.fram2]]" },
81: { CMD_PLAY, "play", 1, "track1[.index1] [track2[.index2]]" },
82: { CMD_PLAY, "play", 1, "tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]]" },
83: { CMD_PLAY, "play", 1, "[#block [len]]" },
1.5 angelos 84: { CMD_PREV, "previous", 2, "" },
1.1 downsj 85: { CMD_QUIT, "quit", 1, "" },
86: { CMD_RESET, "reset", 4, "" },
87: { CMD_RESUME, "resume", 1, "" },
1.6 angelos 88: { CMD_REPLAY, "replay", 3, "" },
1.1 downsj 89: { CMD_SET, "set", 2, "msf | lba" },
90: { CMD_STATUS, "status", 1, "" },
91: { CMD_STOP, "stop", 3, "" },
92: { CMD_VOLUME, "volume", 1, "<l> <r> | left | right | mute | mono | stereo" },
93: { 0, }
94: };
95:
96: struct cd_toc_entry toc_buffer[100];
97:
98: char *cdname;
99: int fd = -1;
100: int verbose = 1;
101: int msf = 1;
102:
103: extern char *__progname;
104:
105: int setvol __P((int, int));
106: int read_toc_entrys __P((int));
107: int play_msf __P((int, int, int, int, int, int));
108: int play_track __P((int, int, int, int));
109: int get_vol __P((int *, int *));
110: int status __P((int *, int *, int *, int *));
111: int open_cd __P((void));
112: int play __P((char *arg));
113: int info __P((char *arg));
114: int pstatus __P((char *arg));
1.5 angelos 115: int play_next __P((char *arg));
116: int play_prev __P((char *arg));
1.6 angelos 117: int play_same __P((char *arg));
1.1 downsj 118: char *input __P((int *));
119: void prtrack __P((struct cd_toc_entry *e, int lastflag));
120: void lba2msf __P((unsigned long lba,
121: u_char *m, u_char *s, u_char *f));
122: unsigned int msf2lba __P((u_char m, u_char s, u_char f));
123: int play_blocks __P((int blk, int len));
124: int run __P((int cmd, char *arg));
125: char *parse __P((char *buf, int *cmd));
126:
127: void help ()
128: {
129: struct cmdtab *c;
130: char *s, n;
131: int i;
132:
133: for (c=cmdtab; c->name; ++c) {
134: if (! c->args)
135: continue;
136: printf("\t");
137: for (i = c->min, s = c->name; *s; s++, i--) {
138: if (i > 0)
139: n = toupper(*s);
140: else
141: n = *s;
142: putchar(n);
143: }
144: if (*c->args)
145: printf (" %s", c->args);
146: printf ("\n");
147: }
148: printf ("\n\tThe word \"play\" is not required for the play commands.\n");
149: printf ("\tThe plain target address is taken as a synonym for play.\n");
150: }
151:
152: void usage ()
153: {
154: printf ("Usage:\n\t%s [ -vs ] [ -f disc ] [ command args... ]\n", __progname);
155: printf ("Options:\n");
156: printf ("\t-v - verbose mode\n");
157: printf ("\t-s - silent mode\n");
158: printf ("\t-f disc - a block device name such as /dev/cd0c\n");
159: printf ("\tMUSIC_CD - shell variable with device name\n");
160: printf ("Commands:\n");
161: help ();
162: exit (1);
163: }
164:
165: int main (argc, argv)
166: int argc;
167: char **argv;
168: {
169: int cmd;
170: char *arg;
171:
172: cdname = getenv ("DISC");
173: if (! cdname)
174: cdname = getenv ("CDROM");
175:
176: for (;;) {
177: switch (getopt (argc, argv, "svhf:")) {
178: case EOF:
179: break;
180: case 's':
181: verbose = 0;
182: continue;
183: case 'v':
184: verbose = 2;
185: continue;
186: case 'f':
187: cdname = optarg;
188: continue;
189: case 'h':
190: default:
191: usage ();
192: }
193: break;
194: }
195: argc -= optind;
196: argv += optind;
197:
198: if (argc > 0 && ! strcasecmp (*argv, "help"))
199: usage ();
200:
201: if (! cdname) {
202: cdname = DEFAULT_CD_DRIVE;
203: fprintf (stderr,
204: "No CD device name specified. Defaulting to %s.\n", cdname);
205: }
206:
207: if (argc > 0) {
208: char buf[80], *p;
209: int len;
210:
211: for (p=buf; argc-->0; ++argv) {
212: len = strlen (*argv);
213:
214: if (p + len >= buf + sizeof (buf) - 1)
215: usage ();
216:
217: if (p > buf)
218: *p++ = ' ';
219:
220: strcpy (p, *argv);
221: p += len;
222: }
223: *p = 0;
224: arg = parse (buf, &cmd);
225: return (run (cmd, arg));
226: }
227:
228: if (verbose == 1)
229: verbose = isatty (0);
230:
231: if (verbose) {
232: printf ("Compact Disc Control utility, version %s\n", VERSION);
233: printf ("Type `?' for command list\n\n");
234: }
235:
236: for (;;) {
237: arg = input (&cmd);
238: if (run (cmd, arg) < 0) {
239: if (verbose)
240: perror (__progname);
241: close (fd);
242: fd = -1;
243: }
244: fflush (stdout);
245: }
246: }
247:
248: int run (cmd, arg)
249: int cmd;
250: char *arg;
251: {
252: int l, r, rc;
253:
254: switch (cmd) {
255:
256: case CMD_QUIT:
257: exit (0);
258:
259: case CMD_INFO:
260: if (fd < 0 && ! open_cd ())
261: return (0);
262:
263: return info (arg);
264:
265: case CMD_STATUS:
266: if (fd < 0 && ! open_cd ())
267: return (0);
268:
269: return pstatus (arg);
270:
271: case CMD_PAUSE:
272: if (fd < 0 && ! open_cd ())
273: return (0);
274:
275: return ioctl (fd, CDIOCPAUSE);
276:
277: case CMD_RESUME:
278: if (fd < 0 && ! open_cd ())
279: return (0);
280:
281: return ioctl (fd, CDIOCRESUME);
282:
283: case CMD_STOP:
284: if (fd < 0 && ! open_cd ())
285: return (0);
286:
287: rc = ioctl (fd, CDIOCSTOP);
288:
289: (void) ioctl (fd, CDIOCALLOW);
290:
291: return (rc);
292:
293: case CMD_RESET:
294: if (fd < 0 && ! open_cd ())
295: return (0);
296:
297: rc = ioctl (fd, CDIOCRESET);
298: if (rc < 0)
299: return rc;
300: close(fd);
301: fd = -1;
302: return (0);
303:
304: case CMD_DEBUG:
305: if (fd < 0 && ! open_cd ())
306: return (0);
307:
308: if (! strcasecmp (arg, "on"))
309: return ioctl (fd, CDIOCSETDEBUG);
310:
311: if (! strcasecmp (arg, "off"))
312: return ioctl (fd, CDIOCCLRDEBUG);
313:
314: printf ("%s: Invalid command arguments\n", __progname);
315:
316: return (0);
317:
318: case CMD_EJECT:
319: if (fd < 0 && ! open_cd ())
320: return (0);
321:
322: (void) ioctl (fd, CDIOCALLOW);
323: rc = ioctl (fd, CDIOCEJECT);
324: if (rc < 0)
325: return (rc);
326: #if defined(__OpenBSD__)
327: close(fd);
328: fd = -1;
329: #endif
330: return (0);
331:
332: case CMD_CLOSE:
333: #if defined(CDIOCCLOSE)
334: if (fd < 0 && ! open_cd ())
335: return (0);
336:
337: (void) ioctl (fd, CDIOCALLOW);
338: rc = ioctl (fd, CDIOCCLOSE);
339: if (rc < 0)
340: return (rc);
341: close(fd);
342: fd = -1;
343: return (0);
344: #else
345: printf ("%s: Command not yet supported\n", __progname);
346: return (0);
347: #endif
348:
349: case CMD_PLAY:
350: if (fd < 0 && ! open_cd ())
351: return (0);
352:
353: while (isspace (*arg))
354: arg++;
355:
356: return play (arg);
357:
358: case CMD_SET:
359: if (! strcasecmp (arg, "msf"))
360: msf = 1;
361: else if (! strcasecmp (arg, "lba"))
362: msf = 0;
363: else
364: printf ("%s: Invalid command arguments\n", __progname);
365: return (0);
366:
367: case CMD_VOLUME:
368: if (fd < 0 && !open_cd ())
369: return (0);
370:
371: if (! strncasecmp (arg, "left", strlen(arg)))
372: return ioctl (fd, CDIOCSETLEFT);
373:
374: if (! strncasecmp (arg, "right", strlen(arg)))
375: return ioctl (fd, CDIOCSETRIGHT);
376:
377: if (! strncasecmp (arg, "mono", strlen(arg)))
378: return ioctl (fd, CDIOCSETMONO);
379:
380: if (! strncasecmp (arg, "stereo", strlen(arg)))
1.8 ! downsj 381: return ioctl (fd, CDIOCSETSTEREO);
1.1 downsj 382:
383: if (! strncasecmp (arg, "mute", strlen(arg)))
384: return ioctl (fd, CDIOCSETMUTE);
385:
386: if (2 != sscanf (arg, "%d %d", &l, &r)) {
387: printf ("%s: Invalid command arguments\n", __progname);
388: return (0);
389: }
390:
391: return setvol (l, r);
392:
1.5 angelos 393: case CMD_NEXT:
394: if (fd < 0 && ! open_cd ())
395: return (0);
396:
397: return play_next (arg);
398:
399: case CMD_PREV:
400: if (fd < 0 && ! open_cd ())
401: return (0);
402:
403: return play_prev (arg);
404:
1.6 angelos 405: case CMD_REPLAY:
406: if (fd < 0 && ! open_cd ())
407: return 0;
408:
409: return play_same (arg);
1.1 downsj 410: default:
411: case CMD_HELP:
412: help ();
413: return (0);
414:
415: }
416: }
417:
418: int play (arg)
419: char *arg;
420: {
421: struct ioc_toc_header h;
422: int rc, n, start, end = 0, istart = 1, iend = 1;
423:
424: rc = ioctl (fd, CDIOREADTOCHEADER, &h);
425:
426: if (rc < 0)
427: return (rc);
428:
429: n = h.ending_track - h.starting_track + 1;
430: rc = read_toc_entrys ((n + 1) * sizeof (struct cd_toc_entry));
431:
432: if (rc < 0)
433: return (rc);
434:
435: if (! arg || ! *arg) {
436: /* Play the whole disc */
437: if (msf)
1.4 niklas 438: return
439: play_blocks (msf2lba (toc_buffer[0].addr.msf.minute,
440: toc_buffer[0].addr.msf.second,
441: toc_buffer[0].addr.msf.frame),
442: msf2lba (toc_buffer[n].addr.msf.minute,
443: toc_buffer[n].addr.msf.second,
444: toc_buffer[n].addr.msf.frame));
1.1 downsj 445: else
1.4 niklas 446: return play_blocks (ntohl (toc_buffer[0].addr.lba),
447: ntohl (toc_buffer[n].addr.lba));
1.1 downsj 448: }
449:
450: if (strchr (arg, '#')) {
451: /* Play block #blk [ len ] */
452: int blk, len = 0;
453:
454: if (2 != sscanf (arg, "#%d%d", &blk, &len) &&
455: 1 != sscanf (arg, "#%d", &blk))
456: goto Clean_up;
457:
458: if (len == 0) {
459: if (msf)
460: len = msf2lba (toc_buffer[n].addr.msf.minute,
461: toc_buffer[n].addr.msf.second,
462: toc_buffer[n].addr.msf.frame) - blk;
463: else
464: len = ntohl(toc_buffer[n].addr.lba) - blk;
465: }
466: return play_blocks (blk, len);
467: }
468:
469: if (strchr (arg, ':')) {
470: /*
471: * Play MSF m1:s1 [ .f1 ] [ m2:s2 [ .f2 ] ]
472: *
473: * Will now also undestand timed addresses relative
474: * to the beginning of a track in the form...
475: *
476: * tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]]
477: */
478: unsigned tr1, tr2;
479: unsigned m1, m2, s1, s2, f1, f2;
480: unsigned char tm, ts, tf;
481:
482: tr2 = m2 = s2 = f2 = f1 = 0;
483: if (8 == sscanf (arg, "%d %d:%d.%d %d %d:%d.%d",
484: &tr1, &m1, &s1, &f1, &tr2, &m2, &s2, &f2))
485: goto Play_Relative_Addresses;
486:
487: tr2 = m2 = s2 = f2 = f1 = 0;
488: if (7 == sscanf (arg, "%d %d:%d %d %d:%d.%d",
489: &tr1, &m1, &s1, &tr2, &m2, &s2, &f2))
490: goto Play_Relative_Addresses;
491:
492: tr2 = m2 = s2 = f2 = f1 = 0;
493: if (7 == sscanf (arg, "%d %d:%d.%d %d %d:%d",
494: &tr1, &m1, &s1, &f1, &tr2, &m2, &s2))
495: goto Play_Relative_Addresses;
496:
497: tr2 = m2 = s2 = f2 = f1 = 0;
498: if (7 == sscanf (arg, "%d %d:%d.%d %d:%d.%d",
499: &tr1, &m1, &s1, &f1, &m2, &s2, &f2))
500: goto Play_Relative_Addresses;
501:
502: tr2 = m2 = s2 = f2 = f1 = 0;
503: if (6 == sscanf (arg, "%d %d:%d.%d %d:%d",
504: &tr1, &m1, &s1, &f1, &m2, &s2))
505: goto Play_Relative_Addresses;
506:
507: tr2 = m2 = s2 = f2 = f1 = 0;
508: if (6 == sscanf (arg, "%d %d:%d %d:%d.%d",
509: &tr1, &m1, &s1, &m2, &s2, &f2))
510: goto Play_Relative_Addresses;
511:
512: tr2 = m2 = s2 = f2 = f1 = 0;
513: if (6 == sscanf (arg, "%d %d:%d.%d %d %d",
514: &tr1, &m1, &s1, &f1, &tr2, &m2))
515: goto Play_Relative_Addresses;
516:
517: tr2 = m2 = s2 = f2 = f1 = 0;
518: if (5 == sscanf (arg, "%d %d:%d %d:%d", &tr1, &m1, &s1, &m2, &s2))
519: goto Play_Relative_Addresses;
520:
521: tr2 = m2 = s2 = f2 = f1 = 0;
522: if (5 == sscanf (arg, "%d %d:%d %d %d",
523: &tr1, &m1, &s1, &tr2, &m2))
524: goto Play_Relative_Addresses;
525:
526: tr2 = m2 = s2 = f2 = f1 = 0;
527: if (5 == sscanf (arg, "%d %d:%d.%d %d",
528: &tr1, &m1, &s1, &f1, &tr2))
529: goto Play_Relative_Addresses;
530:
531: tr2 = m2 = s2 = f2 = f1 = 0;
532: if (4 == sscanf (arg, "%d %d:%d %d", &tr1, &m1, &s1, &tr2))
533: goto Play_Relative_Addresses;
534:
535: tr2 = m2 = s2 = f2 = f1 = 0;
536: if (4 == sscanf (arg, "%d %d:%d.%d", &tr1, &m1, &s1, &f1))
537: goto Play_Relative_Addresses;
538:
539: tr2 = m2 = s2 = f2 = f1 = 0;
540: if (3 == sscanf (arg, "%d %d:%d", &tr1, &m1, &s1))
541: goto Play_Relative_Addresses;
542:
543: tr2 = m2 = s2 = f2 = f1 = 0;
544: goto Try_Absolute_Timed_Addresses;
545:
546: Play_Relative_Addresses:
547: if (! tr1)
548: tr1 = 1;
549: else if (tr1 > n)
550: tr1 = n;
551:
552: if (msf) {
553: tm = toc_buffer[tr1].addr.msf.minute;
554: ts = toc_buffer[tr1].addr.msf.second;
555: tf = toc_buffer[tr1].addr.msf.frame;
556: } else
557: lba2msf(ntohl(toc_buffer[tr1].addr.lba),
558: &tm, &ts, &tf);
559: if ((m1 > tm)
560: || ((m1 == tm)
561: && ((s1 > ts)
562: || ((s1 == ts)
563: && (f1 > tf))))) {
564: printf ("Track %d is not that long.\n", tr1);
565: return (0);
566: }
567:
568: tr1--;
569:
570: f1 += tf;
571: if (f1 >= 75) {
572: s1 += f1 / 75;
573: f1 %= 75;
574: }
575:
576: s1 += ts;
577: if (s1 >= 60) {
578: m1 += s1 / 60;
579: s1 %= 60;
580: }
581:
582: m1 += tm;
583:
584: if (! tr2) {
585: if (m2 || s2 || f2) {
586: tr2 = tr1;
587: f2 += f1;
588: if (f2 >= 75) {
589: s2 += f2 / 75;
590: f2 %= 75;
591: }
592:
593: s2 += s1;
594: if (s2 > 60) {
595: m2 += s2 / 60;
596: s2 %= 60;
597: }
598:
599: m2 += m1;
600: } else {
601: tr2 = n;
602: if (msf) {
603: m2 = toc_buffer[n].addr.msf.minute;
604: s2 = toc_buffer[n].addr.msf.second;
605: f2 = toc_buffer[n].addr.msf.frame;
606: } else {
607: lba2msf(ntohl(toc_buffer[n].addr.lba),
608: &tm, &ts, &tf);
609: m2 = tm;
610: s2 = ts;
611: f2 = tf;
612: }
613: }
614: } else if (tr2 > n) {
615: tr2 = n;
616: m2 = s2 = f2 = 0;
617: } else {
618: if (m2 || s2 || f2)
619: tr2--;
620: if (msf) {
621: tm = toc_buffer[tr2].addr.msf.minute;
622: ts = toc_buffer[tr2].addr.msf.second;
623: tf = toc_buffer[tr2].addr.msf.frame;
624: } else
625: lba2msf(ntohl(toc_buffer[tr2].addr.lba),
626: &tm, &ts, &tf);
627: f2 += tf;
628: if (f2 >= 75) {
629: s2 += f2 / 75;
630: f2 %= 75;
631: }
632:
633: s2 += ts;
634: if (s2 > 60) {
635: m2 += s2 / 60;
636: s2 %= 60;
637: }
638:
639: m2 += tm;
640: }
641:
642: if (msf) {
643: tm = toc_buffer[n].addr.msf.minute;
644: ts = toc_buffer[n].addr.msf.second;
645: tf = toc_buffer[n].addr.msf.frame;
646: } else
647: lba2msf(ntohl(toc_buffer[n].addr.lba),
648: &tm, &ts, &tf);
649: if ((tr2 < n)
650: && ((m2 > tm)
651: || ((m2 == tm)
652: && ((s2 > ts)
653: || ((s2 == ts)
654: && (f2 > tf)))))) {
655: printf ("The playing time of the disc is not that long.\n");
656: return (0);
657: }
658: return (play_msf (m1, s1, f1, m2, s2, f2));
659:
660: Try_Absolute_Timed_Addresses:
661: if (6 != sscanf (arg, "%d:%d.%d%d:%d.%d",
662: &m1, &s1, &f1, &m2, &s2, &f2) &&
663: 5 != sscanf (arg, "%d:%d.%d%d:%d", &m1, &s1, &f1, &m2, &s2) &&
664: 5 != sscanf (arg, "%d:%d%d:%d.%d", &m1, &s1, &m2, &s2, &f2) &&
665: 3 != sscanf (arg, "%d:%d.%d", &m1, &s1, &f1) &&
666: 4 != sscanf (arg, "%d:%d%d:%d", &m1, &s1, &m2, &s2) &&
667: 2 != sscanf (arg, "%d:%d", &m1, &s1))
668: goto Clean_up;
669:
670: if (m2 == 0) {
671: if (msf) {
672: m2 = toc_buffer[n].addr.msf.minute;
673: s2 = toc_buffer[n].addr.msf.second;
674: f2 = toc_buffer[n].addr.msf.frame;
675: } else {
676: lba2msf(ntohl(toc_buffer[n].addr.lba),
677: &tm, &ts, &tf);
678: m2 = tm;
679: s2 = ts;
680: f2 = tf;
681: }
682: }
683: return play_msf (m1, s1, f1, m2, s2, f2);
684: }
685:
686: /*
687: * Play track trk1 [ .idx1 ] [ trk2 [ .idx2 ] ]
688: */
689: if (4 != sscanf (arg, "%d.%d%d.%d", &start, &istart, &end, &iend) &&
690: 3 != sscanf (arg, "%d.%d%d", &start, &istart, &end) &&
691: 3 != sscanf (arg, "%d%d.%d", &start, &end, &iend) &&
692: 2 != sscanf (arg, "%d.%d", &start, &istart) &&
693: 2 != sscanf (arg, "%d%d", &start, &end) &&
694: 1 != sscanf (arg, "%d", &start))
695: goto Clean_up;
696:
697: if (end == 0)
698: end = n;
699: return (play_track (start, istart, end, iend));
700:
701: Clean_up:
702: printf ("%s: Invalid command arguments\n", __progname);
1.5 angelos 703: return (0);
704: }
705:
706: int play_prev (arg)
707: char *arg;
708: {
709: int trk, min, sec, frm, rc;
710: struct ioc_toc_header h;
711:
712: if (status (&trk, &min, &sec, &frm) >= 0)
713: {
714: trk--;
715:
716: rc = ioctl (fd, CDIOREADTOCHEADER, &h);
717: if (rc < 0)
718: {
719: perror ("getting toc header");
720: return (rc);
721: }
722:
723: if (trk < h.starting_track)
724: return play_track (h.starting_track, 1,
1.7 angelos 725: h.ending_track + 1, 1);
1.6 angelos 726:
1.7 angelos 727: return play_track (trk, 1, h.ending_track, 1);
1.6 angelos 728: }
729:
730: return (0);
731: }
732:
733: int play_same (arg)
734: char *arg;
735: {
736: int trk, min, sec, frm, rc;
737: struct ioc_toc_header h;
738:
739: if (status (&trk, &min, &sec, &frm) >= 0)
740: {
741: rc = ioctl (fd, CDIOREADTOCHEADER, &h);
742: if (rc < 0)
743: {
744: perror ("getting toc header");
745: return (rc);
746: }
1.5 angelos 747:
1.7 angelos 748: return play_track (trk, 1, h.ending_track, 1);
1.5 angelos 749: }
750:
751: return (0);
752: }
753:
754: int play_next (arg)
755: char *arg;
756: {
757: int trk, min, sec, frm, rc;
758: struct ioc_toc_header h;
759:
760: if (status (&trk, &min, &sec, &frm) >= 0)
761: {
762: trk++;
763: rc = ioctl (fd, CDIOREADTOCHEADER, &h);
764: if (rc < 0)
765: {
766: perror ("getting toc header");
767: return (rc);
768: }
769:
770: if (trk > h.ending_track)
771: {
772: printf("%s: end of CD\n", __progname);
773:
774: rc = ioctl (fd, CDIOCSTOP);
775:
776: (void) ioctl (fd, CDIOCALLOW);
777:
778: return (rc);
779: }
780:
1.7 angelos 781: return play_track (trk, 1, h.ending_track, 1);
1.5 angelos 782: }
783:
1.1 downsj 784: return (0);
785: }
786:
787: char *strstatus (sts)
788: int sts;
789: {
790: switch (sts) {
791: case ASTS_INVALID: return ("invalid");
792: case ASTS_PLAYING: return ("playing");
793: case ASTS_PAUSED: return ("paused");
794: case ASTS_COMPLETED: return ("completed");
795: case ASTS_ERROR: return ("error");
796: case ASTS_VOID: return ("void");
797: default: return ("??");
798: }
799: }
800:
801: int pstatus (arg)
802: char *arg;
803: {
804: struct ioc_vol v;
805: struct ioc_read_subchannel ss;
806: struct cd_sub_channel_info data;
807: int rc, trk, m, s, f;
808:
809: rc = status (&trk, &m, &s, &f);
810: if (rc >= 0)
811: if (verbose)
812: printf ("Audio status = %d<%s>, current track = %d, current position = %d:%02d.%02d\n",
813: rc, strstatus (rc), trk, m, s, f);
814: else
815: printf ("%d %d %d:%02d.%02d\n", rc, trk, m, s, f);
816: else
817: printf ("No current status info available\n");
818:
819: bzero (&ss, sizeof (ss));
820: ss.data = &data;
821: ss.data_len = sizeof (data);
822: ss.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT;
823: ss.data_format = CD_MEDIA_CATALOG;
824: rc = ioctl (fd, CDIOCREADSUBCHANNEL, (char *) &ss);
825: if (rc >= 0) {
826: printf("Media catalog is %sactive",
827: ss.data->what.media_catalog.mc_valid ? "": "in");
828: if (ss.data->what.media_catalog.mc_valid &&
829: ss.data->what.media_catalog.mc_number[0])
830: printf(", number \"%.15s\"",
831: ss.data->what.media_catalog.mc_number);
832: putchar('\n');
833: } else
834: printf("No media catalog info available\n");
835:
836: rc = ioctl (fd, CDIOCGETVOL, &v);
837: if (rc >= 0)
838: if (verbose)
839: printf ("Left volume = %d, right volume = %d\n",
840: v.vol[0], v.vol[1]);
841: else
842: printf ("%d %d\n", v.vol[0], v.vol[1]);
843: else
844: printf ("No volume level info available\n");
845: return(0);
846: }
847:
848: int info (arg)
849: char *arg;
850: {
851: struct ioc_toc_header h;
852: int rc, i, n;
853:
854: rc = ioctl (fd, CDIOREADTOCHEADER, &h);
855: if (rc >= 0) {
856: if (verbose)
857: printf ("Starting track = %d, ending track = %d, TOC size = %d bytes\n",
858: h.starting_track, h.ending_track, h.len);
859: else
860: printf ("%d %d %d\n", h.starting_track,
861: h.ending_track, h.len);
862: } else {
863: perror ("getting toc header");
864: return (rc);
865: }
866:
867: n = h.ending_track - h.starting_track + 1;
868: rc = read_toc_entrys ((n + 1) * sizeof (struct cd_toc_entry));
869: if (rc < 0)
870: return (rc);
871:
872: if (verbose) {
873: printf ("track start duration block length type\n");
874: printf ("-------------------------------------------------\n");
875: }
876:
877: for (i = 0; i < n; i++) {
878: printf ("%5d ", toc_buffer[i].track);
879: prtrack (toc_buffer + i, 0);
880: }
881: printf ("%5d ", toc_buffer[n].track);
882: prtrack (toc_buffer + n, 1);
883: return (0);
884: }
885:
886: void lba2msf (lba, m, s, f)
887: unsigned long lba;
888: u_char *m;
889: u_char *s;
890: u_char *f;
891: {
892: lba += 150; /* block start offset */
893: lba &= 0xffffff; /* negative lbas use only 24 bits */
894: *m = lba / (60 * 75);
895: lba %= (60 * 75);
896: *s = lba / 75;
897: *f = lba % 75;
898: }
899:
900: unsigned int msf2lba (m, s, f)
901: u_char m;
902: u_char s;
903: u_char f;
904: {
905: return (((m * 60) + s) * 75 + f) - 150;
906: }
907:
908: void prtrack (e, lastflag)
909: struct cd_toc_entry *e;
910: int lastflag;
911: {
912: int block, next, len;
913: u_char m, s, f;
914:
915: if (msf) {
916: /* Print track start */
917: printf ("%2d:%02d.%02d ", e->addr.msf.minute,
918: e->addr.msf.second, e->addr.msf.frame);
919:
920: block = msf2lba (e->addr.msf.minute, e->addr.msf.second,
921: e->addr.msf.frame);
922: } else {
923: block = ntohl(e->addr.lba);
924: lba2msf(block, &m, &s, &f);
925: /* Print track start */
926: printf ("%2d:%02d.%02d ", m, s, f);
927: }
928: if (lastflag) {
929: /* Last track -- print block */
930: printf (" - %6d - -\n", block);
931: return;
932: }
933:
934: if (msf)
935: next = msf2lba (e[1].addr.msf.minute, e[1].addr.msf.second,
936: e[1].addr.msf.frame);
937: else
938: next = ntohl(e[1].addr.lba);
939: len = next - block;
940: lba2msf (len, &m, &s, &f);
941:
942: /* Print duration, block, length, type */
943: printf ("%2d:%02d.%02d %6d %6d %5s\n", m, s, f, block, len,
944: (e->control & 4) ? "data" : "audio");
945: }
946:
947: int play_track (tstart, istart, tend, iend)
948: int tstart;
949: int istart;
950: int tend;
951: int iend;
952: {
953: struct ioc_play_track t;
954:
955: t.start_track = tstart;
956: t.start_index = istart;
957: t.end_track = tend;
958: t.end_index = iend;
959:
960: return ioctl (fd, CDIOCPLAYTRACKS, &t);
961: }
962:
963: int play_blocks (blk, len)
964: int blk;
965: int len;
966: {
967: struct ioc_play_blocks t;
968:
969: t.blk = blk;
970: t.len = len;
971:
972: return ioctl (fd, CDIOCPLAYBLOCKS, &t);
973: }
974:
975: int setvol (left, right)
976: int left;
977: int right;
978: {
979: struct ioc_vol v;
980:
981: v.vol[0] = left;
982: v.vol[1] = right;
983: v.vol[2] = 0;
984: v.vol[3] = 0;
985:
986: return ioctl (fd, CDIOCSETVOL, &v);
987: }
988:
989: int read_toc_entrys (len)
990: int len;
991: {
992: struct ioc_read_toc_entry t;
993:
994: t.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT;
995: t.starting_track = 0;
996: t.data_len = len;
997: t.data = toc_buffer;
998:
999: return (ioctl (fd, CDIOREADTOCENTRYS, (char *) &t));
1000: }
1001:
1002: int play_msf (start_m, start_s, start_f, end_m, end_s, end_f)
1003: int start_m;
1004: int start_s;
1005: int start_f;
1006: int end_m;
1007: int end_s;
1008: int end_f;
1009: {
1010: struct ioc_play_msf a;
1011:
1012: a.start_m = start_m;
1013: a.start_s = start_s;
1014: a.start_f = start_f;
1015: a.end_m = end_m;
1016: a.end_s = end_s;
1017: a.end_f = end_f;
1018:
1019: return ioctl (fd, CDIOCPLAYMSF, (char *) &a);
1020: }
1021:
1022: int status (trk, min, sec, frame)
1023: int *trk;
1024: int *min;
1025: int *sec;
1026: int *frame;
1027: {
1028: struct ioc_read_subchannel s;
1029: struct cd_sub_channel_info data;
1030: u_char mm, ss, ff;
1031:
1032: bzero (&s, sizeof (s));
1033: s.data = &data;
1034: s.data_len = sizeof (data);
1035: s.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT;
1036: s.data_format = CD_CURRENT_POSITION;
1037:
1038: if (ioctl (fd, CDIOCREADSUBCHANNEL, (char *) &s) < 0)
1039: return -1;
1040:
1041: *trk = s.data->what.position.track_number;
1042: if (msf) {
1043: *min = s.data->what.position.reladdr.msf.minute;
1044: *sec = s.data->what.position.reladdr.msf.second;
1045: *frame = s.data->what.position.reladdr.msf.frame;
1046: } else {
1047: lba2msf(ntohl(s.data->what.position.reladdr.lba),
1048: &mm, &ss, &ff);
1049: *min = mm;
1050: *sec = ss;
1051: *frame = ff;
1052: }
1053:
1054: return s.data->header.audio_status;
1055: }
1056:
1057: char *input (cmd)
1058: int *cmd;
1059: {
1060: static char buf[80];
1061: char *p;
1062:
1063: do {
1064: if (verbose)
1065: fprintf (stderr, "%s> ", __progname);
1066: if (! fgets (buf, sizeof (buf), stdin)) {
1067: *cmd = CMD_QUIT;
1068: fprintf (stderr, "\r\n");
1069: return (0);
1070: }
1071: p = parse (buf, cmd);
1072: } while (! p);
1073: return (p);
1074: }
1075:
1076: char *parse (buf, cmd)
1077: char *buf;
1078: int *cmd;
1079: {
1080: struct cmdtab *c;
1081: char *p;
1082: int len;
1083:
1084: for (p=buf; isspace (*p); p++)
1085: continue;
1086:
1087: if (isdigit (*p) || (p[0] == '#' && isdigit (p[1]))) {
1088: *cmd = CMD_PLAY;
1089: return (p);
1090: }
1091:
1092: for (buf = p; *p && ! isspace (*p); p++)
1093: continue;
1094:
1095: len = p - buf;
1096: if (! len)
1097: return (0);
1098:
1099: if (*p) { /* It must be a spacing character! */
1100: char *q;
1101:
1102: *p++ = 0;
1103: for (q=p; *q && *q != '\n' && *q != '\r'; q++)
1104: continue;
1105: *q = 0;
1106: }
1107:
1108: *cmd = -1;
1109: for (c=cmdtab; c->name; ++c) {
1110: /* Is it an exact match? */
1111: if (! strcasecmp (buf, c->name)) {
1112: *cmd = c->command;
1113: break;
1114: }
1115:
1116: /* Try short hand forms then... */
1117: if (len >= c->min && ! strncasecmp (buf, c->name, len)) {
1118: if (*cmd != -1 && *cmd != c->command) {
1119: fprintf (stderr, "Ambiguous command\n");
1120: return (0);
1121: }
1122: *cmd = c->command;
1123: }
1124: }
1125:
1126: if (*cmd == -1) {
1127: fprintf (stderr, "%s: Invalid command, enter ``help'' for commands.\n",
1128: __progname);
1129: return (0);
1130: }
1131:
1132: while (isspace (*p))
1133: p++;
1134: return p;
1135: }
1136:
1137: int open_cd ()
1138: {
1139: char *dev;
1140:
1141: if (fd > -1)
1142: return (1);
1143:
1144: fd = opendev(cdname, O_RDONLY, OPENDEV_PART, &dev);
1145: if (fd < 0) {
1146: if ((errno == ENXIO) || (errno == EIO)) {
1147: /* ENXIO has an overloaded meaning here.
1148: * The original "Device not configured" should
1149: * be interpreted as "No disc in drive %s". */
1150: fprintf (stderr, "%s: No disc in drive %s.\n", __progname, dev);
1151: return (0);
1152: }
1153: perror (dev);
1154: exit (1);
1155: }
1156: return (1);
1157: }