Annotation of src/usr.bin/cdio/cdio.c, Revision 1.46
1.46 ! krw 1: /* $OpenBSD: cdio.c,v 1.45 2006/01/10 19:59:11 krw Exp $ */
1.28 jmc 2:
3: /* Copyright (c) 1995 Serge V. Vakulenko
4: * All rights reserved.
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: *
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed by Serge V. Vakulenko.
18: * 4. The name of the author may not be used to endorse or promote products
19: * derived from this software without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31: */
32:
1.1 downsj 33: /*
34: * Compact Disc Control Utility by Serge V. Vakulenko <vak@cronyx.ru>.
35: * Based on the non-X based CD player by Jean-Marc Zucconi and
36: * Andrey A. Chernov.
37: *
38: * Fixed and further modified on 5-Sep-1995 by Jukka Ukkonen <jau@funet.fi>.
39: *
40: * 11-Sep-1995: Jukka A. Ukkonen <jau@funet.fi>
41: * A couple of further fixes to my own earlier "fixes".
42: *
43: * 18-Sep-1995: Jukka A. Ukkonen <jau@funet.fi>
44: * Added an ability to specify addresses relative to the
45: * beginning of a track. This is in fact a variation of
46: * doing the simple play_msf() call.
47: *
48: * 11-Oct-1995: Serge V.Vakulenko <vak@cronyx.ru>
49: * New eject algorithm.
50: * Some code style reformatting.
51: *
52: * $FreeBSD: cdcontrol.c,v 1.13 1996/06/25 21:01:27 ache Exp $
53: */
54:
1.27 fgsch 55: #include <sys/param.h>
56: #include <sys/file.h>
57: #include <sys/cdio.h>
58: #include <sys/ioctl.h>
59:
1.1 downsj 60: #include <ctype.h>
1.17 espie 61: #include <err.h>
62: #include <errno.h>
1.1 downsj 63: #include <stdio.h>
64: #include <stdlib.h>
65: #include <string.h>
66: #include <unistd.h>
1.27 fgsch 67: #include <histedit.h>
1.1 downsj 68: #include <util.h>
1.17 espie 69: #include <vis.h>
1.27 fgsch 70:
1.24 espie 71: #include "extern.h"
1.1 downsj 72:
73: #define ASTS_INVALID 0x00 /* Audio status byte not valid */
74: #define ASTS_PLAYING 0x11 /* Audio play operation in progress */
75: #define ASTS_PAUSED 0x12 /* Audio play operation paused */
76: #define ASTS_COMPLETED 0x13 /* Audio play operation successfully completed */
77: #define ASTS_ERROR 0x14 /* Audio play operation stopped due to error */
78: #define ASTS_VOID 0x15 /* No current audio status to return */
79:
80: #ifndef DEFAULT_CD_DRIVE
1.3 deraadt 81: # define DEFAULT_CD_DRIVE "cd0"
1.1 downsj 82: #endif
83:
84: #define CMD_DEBUG 1
1.9 millert 85: #define CMD_DEVICE 2
86: #define CMD_EJECT 3
87: #define CMD_HELP 4
88: #define CMD_INFO 5
89: #define CMD_PAUSE 6
90: #define CMD_PLAY 7
91: #define CMD_QUIT 8
92: #define CMD_RESUME 9
93: #define CMD_STOP 10
94: #define CMD_VOLUME 11
95: #define CMD_CLOSE 12
96: #define CMD_RESET 13
97: #define CMD_SET 14
98: #define CMD_STATUS 15
99: #define CMD_NEXT 16
100: #define CMD_PREV 17
101: #define CMD_REPLAY 18
1.24 espie 102: #define CMD_CDDB 19
1.25 espie 103: #define CMD_CDID 20
1.1 downsj 104:
105: struct cmdtab {
106: int command;
107: char *name;
1.24 espie 108: unsigned int min;
1.1 downsj 109: char *args;
110: } cmdtab[] = {
111: { CMD_CLOSE, "close", 1, "" },
1.37 alek 112: { CMD_DEBUG, "debug", 3, "on | off" },
1.9 millert 113: { CMD_DEVICE, "device", 1, "devname" },
1.1 downsj 114: { CMD_EJECT, "eject", 1, "" },
115: { CMD_HELP, "?", 1, 0 },
116: { CMD_HELP, "help", 1, "" },
117: { CMD_INFO, "info", 1, "" },
1.5 angelos 118: { CMD_NEXT, "next", 1, "" },
1.1 downsj 119: { CMD_PAUSE, "pause", 2, "" },
120: { CMD_PLAY, "play", 1, "min1:sec1[.fram1] [min2:sec2[.fram2]]" },
121: { CMD_PLAY, "play", 1, "track1[.index1] [track2[.index2]]" },
122: { CMD_PLAY, "play", 1, "tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]]" },
123: { CMD_PLAY, "play", 1, "[#block [len]]" },
1.5 angelos 124: { CMD_PREV, "previous", 2, "" },
1.1 downsj 125: { CMD_QUIT, "quit", 1, "" },
126: { CMD_RESET, "reset", 4, "" },
127: { CMD_RESUME, "resume", 1, "" },
1.6 angelos 128: { CMD_REPLAY, "replay", 3, "" },
1.1 downsj 129: { CMD_SET, "set", 2, "msf | lba" },
130: { CMD_STATUS, "status", 1, "" },
131: { CMD_STOP, "stop", 3, "" },
132: { CMD_VOLUME, "volume", 1, "<l> <r> | left | right | mute | mono | stereo" },
1.25 espie 133: { CMD_CDDB, "cddbinfo", 2, "[n]" },
1.26 fgsch 134: { CMD_CDID, "cdid", 3, "" },
1.40 millert 135: { CMD_QUIT, "exit", 2, "" },
1.24 espie 136: { 0, 0, 0, 0}
1.1 downsj 137: };
138:
1.11 csapuntz 139: struct cd_toc_entry *toc_buffer;
1.1 downsj 140:
141: char *cdname;
142: int fd = -1;
143: int verbose = 1;
144: int msf = 1;
1.24 espie 145: const char *cddb_host;
146: char **track_names;
1.1 downsj 147:
1.27 fgsch 148: EditLine *el = NULL; /* line-editing structure */
149: History *hist = NULL; /* line-editing history */
150: void switch_el(void);
151:
1.1 downsj 152: extern char *__progname;
153:
1.19 millert 154: int setvol(int, int);
155: int read_toc_entrys(int);
156: int play_msf(int, int, int, int, int, int);
157: int play_track(int, int, int, int);
158: int get_vol(int *, int *);
159: int status(int *, int *, int *, int *);
160: int open_cd(char *);
161: int play(char *arg);
162: int info(char *arg);
1.24 espie 163: int cddbinfo(char *arg);
1.19 millert 164: int pstatus(char *arg);
165: int play_next(char *arg);
166: int play_prev(char *arg);
167: int play_same(char *arg);
168: char *input(int *);
1.27 fgsch 169: char *prompt(void);
1.24 espie 170: void prtrack(struct cd_toc_entry *e, int lastflag, char *name);
1.20 millert 171: void lba2msf(unsigned long lba, u_char *m, u_char *s, u_char *f);
1.19 millert 172: unsigned int msf2lba(u_char m, u_char s, u_char f);
173: int play_blocks(int blk, int len);
174: int run(int cmd, char *arg);
175: char *parse(char *buf, int *cmd);
1.23 espie 176: void help(void);
177: void usage(void);
178: char *strstatus(int);
1.25 espie 179: int cdid(void);
1.42 krw 180: void addmsf(u_int *, u_int *, u_int *, u_char, u_char, u_char);
1.44 krw 181: int cmpmsf(u_char, u_char, u_char, u_char, u_char, u_char);
1.43 krw 182: void toc2msf(u_int, u_char *, u_char *, u_char *);
1.1 downsj 183:
1.18 deraadt 184: void
1.30 deraadt 185: help(void)
1.1 downsj 186: {
187: struct cmdtab *c;
188: char *s, n;
189: int i;
190:
191: for (c=cmdtab; c->name; ++c) {
192: if (! c->args)
193: continue;
194: printf("\t");
195: for (i = c->min, s = c->name; *s; s++, i--) {
196: if (i > 0)
197: n = toupper(*s);
198: else
199: n = *s;
200: putchar(n);
201: }
202: if (*c->args)
1.18 deraadt 203: printf(" %s", c->args);
204: printf("\n");
1.1 downsj 205: }
1.18 deraadt 206: printf("\n\tThe word \"play\" is not required for the play commands.\n");
207: printf("\tThe plain target address is taken as a synonym for play.\n");
1.1 downsj 208: }
209:
1.18 deraadt 210: void
1.30 deraadt 211: usage(void)
1.1 downsj 212: {
1.34 jmc 213: fprintf(stderr, "usage: %s [-sv] [-d host:port] [-f device] [command args ...]\n",
1.18 deraadt 214: __progname);
215: exit(1);
1.1 downsj 216: }
217:
1.18 deraadt 218: int
1.24 espie 219: main(int argc, char **argv)
1.1 downsj 220: {
1.32 miod 221: int ch, cmd;
1.1 downsj 222: char *arg;
223:
1.18 deraadt 224: cdname = getenv("DISC");
1.1 downsj 225: if (! cdname)
1.18 deraadt 226: cdname = getenv("CDROM");
1.1 downsj 227:
1.24 espie 228: cddb_host = getenv("CDDB");
229: if (!cddb_host)
230: cddb_host = "freedb.freedb.org";
231:
1.32 miod 232: while ((ch = getopt(argc, argv, "svd:f:")) != -1)
233: switch (ch) {
1.1 downsj 234: case 's':
235: verbose = 0;
1.32 miod 236: break;
1.1 downsj 237: case 'v':
238: verbose = 2;
1.32 miod 239: break;
1.1 downsj 240: case 'f':
241: cdname = optarg;
1.32 miod 242: break;
1.46 ! krw 243: case 'd':
1.24 espie 244: cddb_host = optarg;
1.32 miod 245: break;
1.1 downsj 246: default:
1.18 deraadt 247: usage();
1.1 downsj 248: }
1.46 ! krw 249:
1.1 downsj 250: argc -= optind;
251: argv += optind;
252:
1.18 deraadt 253: if (argc > 0 && ! strcasecmp(*argv, "help"))
254: usage();
1.1 downsj 255:
256: if (! cdname) {
257: cdname = DEFAULT_CD_DRIVE;
1.18 deraadt 258: fprintf(stderr,
259: "No CD device name specified. Defaulting to %s.\n", cdname);
1.1 downsj 260: }
261:
262: if (argc > 0) {
263: char buf[80], *p;
264: int len;
265:
266: for (p=buf; argc-->0; ++argv) {
1.29 krw 267: len = snprintf(p, buf + sizeof buf - p,
268: "%s%s", (p > buf) ? " " : "", *argv);
1.1 downsj 269:
1.36 moritz 270: if (len == -1 || len >= buf + sizeof buf - p)
1.29 krw 271: errx(1, "argument list too long.");
1.1 downsj 272:
273: p += len;
274: }
1.18 deraadt 275: arg = parse(buf, &cmd);
276: return (run(cmd, arg));
1.1 downsj 277: }
278:
279: if (verbose == 1)
1.18 deraadt 280: verbose = isatty(0);
1.1 downsj 281:
282: if (verbose) {
1.18 deraadt 283: printf("Compact Disc Control utility, version %s\n", VERSION);
284: printf("Type `?' for command list\n\n");
1.1 downsj 285: }
286:
1.27 fgsch 287: switch_el();
288:
1.1 downsj 289: for (;;) {
1.18 deraadt 290: arg = input(&cmd);
291: if (run(cmd, arg) < 0) {
1.1 downsj 292: if (verbose)
1.18 deraadt 293: warn(NULL);
294: close(fd);
1.1 downsj 295: fd = -1;
296: }
1.18 deraadt 297: fflush(stdout);
1.1 downsj 298: }
299: }
300:
1.18 deraadt 301: int
1.24 espie 302: run(int cmd, char *arg)
1.1 downsj 303: {
304: int l, r, rc;
1.9 millert 305: static char newcdname[MAXPATHLEN];
1.1 downsj 306:
307: switch (cmd) {
308:
309: case CMD_QUIT:
1.27 fgsch 310: switch_el();
1.18 deraadt 311: exit(0);
1.1 downsj 312:
313: case CMD_INFO:
1.18 deraadt 314: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 315: return (0);
316:
1.18 deraadt 317: return info(arg);
1.1 downsj 318:
1.24 espie 319: case CMD_CDDB:
320: if (fd < 0 && ! open_cd(cdname))
321: return (0);
322:
323: return cddbinfo(arg);
324:
1.25 espie 325: case CMD_CDID:
326: if (fd < 0 && ! open_cd(cdname))
327: return (0);
328: return cdid();
329:
1.1 downsj 330: case CMD_STATUS:
1.18 deraadt 331: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 332: return (0);
333:
1.18 deraadt 334: return pstatus(arg);
1.1 downsj 335:
336: case CMD_PAUSE:
1.18 deraadt 337: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 338: return (0);
339:
1.18 deraadt 340: return ioctl(fd, CDIOCPAUSE);
1.1 downsj 341:
342: case CMD_RESUME:
1.18 deraadt 343: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 344: return (0);
345:
1.18 deraadt 346: return ioctl(fd, CDIOCRESUME);
1.1 downsj 347:
348: case CMD_STOP:
1.18 deraadt 349: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 350: return (0);
351:
1.18 deraadt 352: rc = ioctl(fd, CDIOCSTOP);
1.1 downsj 353:
1.18 deraadt 354: (void) ioctl(fd, CDIOCALLOW);
1.1 downsj 355:
356: return (rc);
357:
358: case CMD_RESET:
1.18 deraadt 359: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 360: return (0);
361:
1.18 deraadt 362: rc = ioctl(fd, CDIOCRESET);
1.1 downsj 363: if (rc < 0)
364: return rc;
365: close(fd);
366: fd = -1;
367: return (0);
368:
369: case CMD_DEBUG:
1.18 deraadt 370: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 371: return (0);
372:
1.18 deraadt 373: if (! strcasecmp(arg, "on"))
374: return ioctl(fd, CDIOCSETDEBUG);
1.1 downsj 375:
1.18 deraadt 376: if (! strcasecmp(arg, "off"))
377: return ioctl(fd, CDIOCCLRDEBUG);
1.1 downsj 378:
1.18 deraadt 379: printf("%s: Invalid command arguments\n", __progname);
1.1 downsj 380:
381: return (0);
382:
1.9 millert 383: case CMD_DEVICE:
384: /* close old device */
385: if (fd > -1) {
1.18 deraadt 386: (void) ioctl(fd, CDIOCALLOW);
1.9 millert 387: close(fd);
388: fd = -1;
1.38 alek 389: }
390:
391: if (strlen(arg) == 0) {
392: printf("%s: Invalid parameter\n", __progname);
393: return (0);
1.9 millert 394: }
395:
396: /* open new device */
1.18 deraadt 397: if (!open_cd(arg))
1.9 millert 398: return (0);
1.16 lebel 399: (void) strlcpy(newcdname, arg, sizeof(newcdname));
1.9 millert 400: cdname = newcdname;
401: return (1);
402:
1.1 downsj 403: case CMD_EJECT:
1.18 deraadt 404: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 405: return (0);
406:
1.18 deraadt 407: (void) ioctl(fd, CDIOCALLOW);
408: rc = ioctl(fd, CDIOCEJECT);
1.1 downsj 409: if (rc < 0)
410: return (rc);
411: #if defined(__OpenBSD__)
412: close(fd);
413: fd = -1;
414: #endif
1.24 espie 415: if (track_names)
416: free_names(track_names);
417: track_names = NULL;
1.1 downsj 418: return (0);
419:
420: case CMD_CLOSE:
421: #if defined(CDIOCCLOSE)
1.18 deraadt 422: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 423: return (0);
424:
1.18 deraadt 425: (void) ioctl(fd, CDIOCALLOW);
426: rc = ioctl(fd, CDIOCCLOSE);
1.1 downsj 427: if (rc < 0)
428: return (rc);
429: close(fd);
430: fd = -1;
431: return (0);
432: #else
1.18 deraadt 433: printf("%s: Command not yet supported\n", __progname);
1.1 downsj 434: return (0);
435: #endif
436:
437: case CMD_PLAY:
1.18 deraadt 438: if (fd < 0 && ! open_cd(cdname))
1.1 downsj 439: return (0);
440:
1.18 deraadt 441: while (isspace(*arg))
1.1 downsj 442: arg++;
443:
1.18 deraadt 444: return play(arg);
1.1 downsj 445:
446: case CMD_SET:
1.18 deraadt 447: if (!strcasecmp(arg, "msf"))
1.1 downsj 448: msf = 1;
1.18 deraadt 449: else if (!strcasecmp(arg, "lba"))
1.1 downsj 450: msf = 0;
451: else
1.18 deraadt 452: printf("%s: Invalid command arguments\n", __progname);
1.1 downsj 453: return (0);
454:
455: case CMD_VOLUME:
1.18 deraadt 456: if (fd < 0 && !open_cd(cdname))
1.1 downsj 457: return (0);
458:
1.18 deraadt 459: if (!strncasecmp(arg, "left", strlen(arg)))
460: return ioctl(fd, CDIOCSETLEFT);
1.1 downsj 461:
1.18 deraadt 462: if (!strncasecmp(arg, "right", strlen(arg)))
463: return ioctl(fd, CDIOCSETRIGHT);
1.1 downsj 464:
1.18 deraadt 465: if (!strncasecmp(arg, "mono", strlen(arg)))
466: return ioctl(fd, CDIOCSETMONO);
1.1 downsj 467:
1.18 deraadt 468: if (!strncasecmp(arg, "stereo", strlen(arg)))
469: return ioctl(fd, CDIOCSETSTEREO);
1.1 downsj 470:
1.18 deraadt 471: if (!strncasecmp(arg, "mute", strlen(arg)))
472: return ioctl(fd, CDIOCSETMUTE);
1.1 downsj 473:
1.18 deraadt 474: if (2 != sscanf(arg, "%d %d", &l, &r)) {
475: printf("%s: Invalid command arguments\n", __progname);
1.1 downsj 476: return (0);
477: }
478:
1.18 deraadt 479: return setvol(l, r);
1.1 downsj 480:
1.18 deraadt 481: case CMD_NEXT:
482: if (fd < 0 && ! open_cd(cdname))
483: return (0);
1.5 angelos 484:
1.18 deraadt 485: return play_next(arg);
1.5 angelos 486:
1.18 deraadt 487: case CMD_PREV:
488: if (fd < 0 && ! open_cd(cdname))
489: return (0);
1.5 angelos 490:
1.18 deraadt 491: return play_prev(arg);
1.5 angelos 492:
1.6 angelos 493: case CMD_REPLAY:
1.18 deraadt 494: if (fd < 0 && ! open_cd(cdname))
1.6 angelos 495: return 0;
496:
1.18 deraadt 497: return play_same(arg);
1.1 downsj 498: default:
499: case CMD_HELP:
1.18 deraadt 500: help();
1.1 downsj 501: return (0);
502:
503: }
504: }
505:
1.18 deraadt 506: int
1.24 espie 507: play(char *arg)
1.1 downsj 508: {
509: struct ioc_toc_header h;
510: int rc, n, start, end = 0, istart = 1, iend = 1;
511:
1.18 deraadt 512: rc = ioctl(fd, CDIOREADTOCHEADER, &h);
1.1 downsj 513:
514: if (rc < 0)
515: return (rc);
516:
517: n = h.ending_track - h.starting_track + 1;
1.18 deraadt 518: rc = read_toc_entrys((n + 1) * sizeof (struct cd_toc_entry));
1.1 downsj 519:
520: if (rc < 0)
521: return (rc);
522:
523: if (! arg || ! *arg) {
524: /* Play the whole disc */
1.46 ! krw 525: return (play_track(h.starting_track, 1,
1.18 deraadt 526: h.ending_track, 1));
1.1 downsj 527: }
528:
1.18 deraadt 529: if (strchr(arg, '#')) {
1.1 downsj 530: /* Play block #blk [ len ] */
531: int blk, len = 0;
532:
1.18 deraadt 533: if (2 != sscanf(arg, "#%d%d", &blk, &len) &&
534: 1 != sscanf(arg, "#%d", &blk))
1.1 downsj 535: goto Clean_up;
536:
537: if (len == 0) {
538: if (msf)
1.18 deraadt 539: len = msf2lba(toc_buffer[n].addr.msf.minute,
540: toc_buffer[n].addr.msf.second,
541: toc_buffer[n].addr.msf.frame) - blk;
1.1 downsj 542: else
1.41 krw 543: len = toc_buffer[n].addr.lba - blk;
1.1 downsj 544: }
1.18 deraadt 545: return play_blocks(blk, len);
1.1 downsj 546: }
547:
1.18 deraadt 548: if (strchr(arg, ':')) {
1.1 downsj 549: /*
550: * Play MSF m1:s1 [ .f1 ] [ m2:s2 [ .f2 ] ]
551: *
552: * Will now also undestand timed addresses relative
553: * to the beginning of a track in the form...
554: *
555: * tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]]
556: */
1.24 espie 557: int tr1, tr2;
558: unsigned int m1, m2, s1, s2, f1, f2;
1.1 downsj 559: unsigned char tm, ts, tf;
560:
561: tr2 = m2 = s2 = f2 = f1 = 0;
1.33 espie 562: if (8 == sscanf(arg, "%d %u:%u.%u %d %u:%u.%u",
1.1 downsj 563: &tr1, &m1, &s1, &f1, &tr2, &m2, &s2, &f2))
564: goto Play_Relative_Addresses;
565:
566: tr2 = m2 = s2 = f2 = f1 = 0;
1.33 espie 567: if (7 == sscanf(arg, "%d %u:%u %d %u:%u.%u",
1.1 downsj 568: &tr1, &m1, &s1, &tr2, &m2, &s2, &f2))
569: goto Play_Relative_Addresses;
570:
571: tr2 = m2 = s2 = f2 = f1 = 0;
1.33 espie 572: if (7 == sscanf(arg, "%d %u:%u.%u %d %u:%u",
1.1 downsj 573: &tr1, &m1, &s1, &f1, &tr2, &m2, &s2))
574: goto Play_Relative_Addresses;
575:
576: tr2 = m2 = s2 = f2 = f1 = 0;
1.33 espie 577: if (7 == sscanf(arg, "%d %u:%u.%u %u:%u.%u",
1.1 downsj 578: &tr1, &m1, &s1, &f1, &m2, &s2, &f2))
579: goto Play_Relative_Addresses;
580:
581: tr2 = m2 = s2 = f2 = f1 = 0;
1.33 espie 582: if (6 == sscanf(arg, "%d %u:%u.%u %u:%u",
1.1 downsj 583: &tr1, &m1, &s1, &f1, &m2, &s2))
584: goto Play_Relative_Addresses;
585:
586: tr2 = m2 = s2 = f2 = f1 = 0;
1.33 espie 587: if (6 == sscanf(arg, "%d %u:%u %u:%u.%u",
1.1 downsj 588: &tr1, &m1, &s1, &m2, &s2, &f2))
589: goto Play_Relative_Addresses;
590:
591: tr2 = m2 = s2 = f2 = f1 = 0;
1.33 espie 592: if (6 == sscanf(arg, "%d %u:%u.%u %d %u",
1.1 downsj 593: &tr1, &m1, &s1, &f1, &tr2, &m2))
594: goto Play_Relative_Addresses;
595:
596: tr2 = m2 = s2 = f2 = f1 = 0;
1.33 espie 597: if (5 == sscanf(arg, "%d %u:%u %u:%u", &tr1, &m1, &s1, &m2, &s2))
1.1 downsj 598: goto Play_Relative_Addresses;
599:
600: tr2 = m2 = s2 = f2 = f1 = 0;
1.33 espie 601: if (5 == sscanf(arg, "%d %u:%u %d %u",
1.1 downsj 602: &tr1, &m1, &s1, &tr2, &m2))
603: goto Play_Relative_Addresses;
604:
605: tr2 = m2 = s2 = f2 = f1 = 0;
1.33 espie 606: if (5 == sscanf(arg, "%d %u:%u.%u %d",
1.1 downsj 607: &tr1, &m1, &s1, &f1, &tr2))
608: goto Play_Relative_Addresses;
609:
610: tr2 = m2 = s2 = f2 = f1 = 0;
1.33 espie 611: if (4 == sscanf(arg, "%d %u:%u %u", &tr1, &m1, &s1, &tr2))
1.1 downsj 612: goto Play_Relative_Addresses;
613:
614: tr2 = m2 = s2 = f2 = f1 = 0;
1.33 espie 615: if (4 == sscanf(arg, "%d %u:%u.%u", &tr1, &m1, &s1, &f1))
1.1 downsj 616: goto Play_Relative_Addresses;
617:
618: tr2 = m2 = s2 = f2 = f1 = 0;
1.33 espie 619: if (3 == sscanf(arg, "%d %u:%u", &tr1, &m1, &s1))
1.1 downsj 620: goto Play_Relative_Addresses;
621:
622: tr2 = m2 = s2 = f2 = f1 = 0;
623: goto Try_Absolute_Timed_Addresses;
624:
625: Play_Relative_Addresses:
1.45 krw 626: if (tr1 < 1 || tr1 > n) {
627: printf("Track %d not found\n", tr1);
628: return (0);
629: } else if (tr2 < 0 || tr2 > n) {
630: printf("Track %d not found\n", tr2);
631: return (0);
632: }
633:
634: /* Change (m1,s1,f1) from tr1 to disc relative. */
635: toc2msf(tr1, &tm, &ts, &tf);
636: addmsf(&m1, &s1, &f1, tm, ts, tf);
1.1 downsj 637:
1.45 krw 638: /* Compare (m1,s1,f1) to start time of next track. */
1.43 krw 639: toc2msf(tr1+1, &tm, &ts, &tf);
1.44 krw 640: if (cmpmsf(m1, s1, f1, tm, ts, tf) == 1) {
1.18 deraadt 641: printf("Track %d is not that long.\n", tr1);
1.1 downsj 642: return (0);
643: }
644:
1.45 krw 645: if (!(tr2 || m2 || s2 || f2)) {
646: /* No end time specified. Play to end of disc. */
647: toc2msf(n+1, &tm, &ts, &tf);
648: m2 = tm;
649: s2 = ts;
650: f2 = tf;
651: } else if (tr2 != 0) {
652: /*
653: * End time specified relative to tr2. Change
654: * (m2,s2,f2) from tr2 to disc relative.
655: */
656: toc2msf(tr2, &tm, &ts, &tf);
657: addmsf(&m2, &s2, &f2, tm, ts, tf);
658: /* Compare (m2,s2,f2) to start time of next track. */
659: toc2msf(tr2+1, &tm, &ts, &tf);
660: if (cmpmsf(m2, s2, f2, tm, ts, tf) == 1) {
661: printf("Track %d is not that long.\n", tr2);
662: return (0);
1.1 downsj 663: }
664: } else {
1.45 krw 665: /*
666: * Duration rather than end time specified. Change
667: * (m2,s2,f2) from (m1,s1,f1) to disc relative.
668: */
669: addmsf(&m2, &s2, &f2, m1, s1, f1);
670: /* Compare (m2,s2,f2) to end of disc. */
1.43 krw 671: toc2msf(tr2+1, &tm, &ts, &tf);
1.45 krw 672: if (cmpmsf(m2, s2, f2, tm, ts, tf) == 1) {
673: printf("Disc is not that long.\n");
674: return (0);
675: }
1.1 downsj 676: }
677:
1.18 deraadt 678: return (play_msf(m1, s1, f1, m2, s2, f2));
1.1 downsj 679:
680: Try_Absolute_Timed_Addresses:
1.33 espie 681: if (6 != sscanf(arg, "%u:%u.%u%u:%u.%u",
1.18 deraadt 682: &m1, &s1, &f1, &m2, &s2, &f2) &&
1.33 espie 683: 5 != sscanf(arg, "%u:%u.%u%u:%u", &m1, &s1, &f1, &m2, &s2) &&
684: 5 != sscanf(arg, "%u:%u%u:%u.%u", &m1, &s1, &m2, &s2, &f2) &&
685: 3 != sscanf(arg, "%u:%u.%u", &m1, &s1, &f1) &&
686: 4 != sscanf(arg, "%u:%u%u:%u", &m1, &s1, &m2, &s2) &&
687: 2 != sscanf(arg, "%u:%u", &m1, &s1))
1.1 downsj 688: goto Clean_up;
689:
690: if (m2 == 0) {
1.43 krw 691: toc2msf(n+1, &tm, &ts, &tf);
692: m2 = tm;
693: s2 = ts;
694: f2 = tf;
1.1 downsj 695: }
1.43 krw 696:
1.18 deraadt 697: return play_msf(m1, s1, f1, m2, s2, f2);
1.1 downsj 698: }
699:
700: /*
701: * Play track trk1 [ .idx1 ] [ trk2 [ .idx2 ] ]
702: */
1.18 deraadt 703: if (4 != sscanf(arg, "%d.%d%d.%d", &start, &istart, &end, &iend) &&
704: 3 != sscanf(arg, "%d.%d%d", &start, &istart, &end) &&
705: 3 != sscanf(arg, "%d%d.%d", &start, &end, &iend) &&
706: 2 != sscanf(arg, "%d.%d", &start, &istart) &&
707: 2 != sscanf(arg, "%d%d", &start, &end) &&
708: 1 != sscanf(arg, "%d", &start))
1.1 downsj 709: goto Clean_up;
710:
711: if (end == 0)
1.10 csapuntz 712: end = h.ending_track;
1.18 deraadt 713: return (play_track(start, istart, end, iend));
1.1 downsj 714:
715: Clean_up:
1.18 deraadt 716: printf("%s: Invalid command arguments\n", __progname);
1.5 angelos 717: return (0);
718: }
719:
1.35 deraadt 720: /* ARGSUSED */
1.18 deraadt 721: int
1.24 espie 722: play_prev(char *arg)
1.5 angelos 723: {
1.18 deraadt 724: int trk, min, sec, frm, rc;
725: struct ioc_toc_header h;
1.5 angelos 726:
1.18 deraadt 727: if (status(&trk, &min, &sec, &frm) >= 0) {
728: trk--;
1.5 angelos 729:
1.18 deraadt 730: rc = ioctl(fd, CDIOREADTOCHEADER, &h);
731: if (rc < 0) {
732: warn("getting toc header");
733: return (rc);
734: }
1.5 angelos 735:
1.18 deraadt 736: if (trk < h.starting_track)
737: return play_track(h.starting_track, 1,
738: h.ending_track + 1, 1);
739: return play_track(trk, 1, h.ending_track, 1);
740: }
1.6 angelos 741:
1.18 deraadt 742: return (0);
1.6 angelos 743: }
744:
1.35 deraadt 745: /* ARGSUSED */
1.18 deraadt 746: int
1.24 espie 747: play_same(char *arg)
1.6 angelos 748: {
1.18 deraadt 749: int trk, min, sec, frm, rc;
750: struct ioc_toc_header h;
1.6 angelos 751:
1.18 deraadt 752: if (status (&trk, &min, &sec, &frm) >= 0) {
753: rc = ioctl(fd, CDIOREADTOCHEADER, &h);
754: if (rc < 0) {
755: warn("getting toc header");
756: return (rc);
757: }
1.5 angelos 758:
1.18 deraadt 759: return play_track(trk, 1, h.ending_track, 1);
760: }
1.5 angelos 761:
1.18 deraadt 762: return (0);
1.5 angelos 763: }
764:
1.35 deraadt 765: /* ARGSUSED */
1.18 deraadt 766: int
1.24 espie 767: play_next(char *arg)
1.5 angelos 768: {
769: int trk, min, sec, frm, rc;
770: struct ioc_toc_header h;
771:
1.18 deraadt 772: if (status(&trk, &min, &sec, &frm) >= 0) {
1.5 angelos 773: trk++;
1.18 deraadt 774: rc = ioctl(fd, CDIOREADTOCHEADER, &h);
775: if (rc < 0) {
776: warn("getting toc header");
1.5 angelos 777: return (rc);
778: }
779:
1.18 deraadt 780: if (trk > h.ending_track) {
1.5 angelos 781: printf("%s: end of CD\n", __progname);
782:
1.18 deraadt 783: rc = ioctl(fd, CDIOCSTOP);
1.5 angelos 784:
1.18 deraadt 785: (void) ioctl(fd, CDIOCALLOW);
1.5 angelos 786:
787: return (rc);
788: }
789:
1.18 deraadt 790: return play_track(trk, 1, h.ending_track, 1);
1.5 angelos 791: }
792:
1.1 downsj 793: return (0);
794: }
795:
1.18 deraadt 796: char *
1.24 espie 797: strstatus(int sts)
1.1 downsj 798: {
799: switch (sts) {
1.18 deraadt 800: case ASTS_INVALID:
801: return ("invalid");
802: case ASTS_PLAYING:
803: return ("playing");
804: case ASTS_PAUSED:
805: return ("paused");
806: case ASTS_COMPLETED:
807: return ("completed");
808: case ASTS_ERROR:
809: return ("error");
810: case ASTS_VOID:
811: return ("void");
812: default:
813: return ("??");
1.1 downsj 814: }
815: }
816:
1.35 deraadt 817: /* ARGSUSED */
1.18 deraadt 818: int
1.24 espie 819: pstatus(char *arg)
1.1 downsj 820: {
821: struct ioc_vol v;
822: struct ioc_read_subchannel ss;
823: struct cd_sub_channel_info data;
824: int rc, trk, m, s, f;
1.17 espie 825: char vis_catalog[1 + 4 * 15];
1.1 downsj 826:
1.18 deraadt 827: rc = status(&trk, &m, &s, &f);
1.9 millert 828: if (rc >= 0) {
1.24 espie 829: if (verbose) {
830: if (track_names)
831: printf("Audio status = %d<%s>, "
832: "current track = %d (%s)\n"
833: "\tcurrent position = %d:%02d.%02d\n",
834: rc, strstatus(rc), trk,
835: trk ? track_names[trk-1] : "", m, s, f);
836: else
837: printf("Audio status = %d<%s>, "
838: "current track = %d, "
839: "current position = %d:%02d.%02d\n",
840: rc, strstatus(rc), trk, m, s, f);
841: } else
1.18 deraadt 842: printf("%d %d %d:%02d.%02d\n", rc, trk, m, s, f);
1.9 millert 843: } else
1.18 deraadt 844: printf("No current status info available\n");
1.1 downsj 845:
1.18 deraadt 846: bzero(&ss, sizeof (ss));
1.1 downsj 847: ss.data = &data;
848: ss.data_len = sizeof (data);
849: ss.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT;
850: ss.data_format = CD_MEDIA_CATALOG;
1.18 deraadt 851: rc = ioctl(fd, CDIOCREADSUBCHANNEL, (char *) &ss);
1.1 downsj 852: if (rc >= 0) {
853: printf("Media catalog is %sactive",
854: ss.data->what.media_catalog.mc_valid ? "": "in");
855: if (ss.data->what.media_catalog.mc_valid &&
1.17 espie 856: ss.data->what.media_catalog.mc_number[0]) {
857: strvisx(vis_catalog,
1.35 deraadt 858: (char *)ss.data->what.media_catalog.mc_number,
1.17 espie 859: 15, VIS_SAFE);
860: printf(", number \"%.15s\"", vis_catalog);
861: }
1.1 downsj 862: putchar('\n');
863: } else
864: printf("No media catalog info available\n");
865:
1.18 deraadt 866: rc = ioctl(fd, CDIOCGETVOL, &v);
1.9 millert 867: if (rc >= 0) {
1.1 downsj 868: if (verbose)
1.18 deraadt 869: printf("Left volume = %d, right volume = %d\n",
1.1 downsj 870: v.vol[0], v.vol[1]);
871: else
1.18 deraadt 872: printf("%d %d\n", v.vol[0], v.vol[1]);
1.9 millert 873: } else
1.18 deraadt 874: printf("No volume level info available\n");
1.1 downsj 875: return(0);
1.25 espie 876: }
877:
878: int
1.30 deraadt 879: cdid(void)
1.25 espie 880: {
881: unsigned long id;
882: struct ioc_toc_header h;
883: int rc, n;
884:
885: rc = ioctl(fd, CDIOREADTOCHEADER, &h);
886: if (rc == -1) {
887: warn("getting toc header");
888: return (rc);
889: }
890:
891: n = h.ending_track - h.starting_track + 1;
892: rc = read_toc_entrys((n + 1) * sizeof (struct cd_toc_entry));
893: if (rc < 0)
894: return (rc);
895:
896: id = cddb_discid(n, toc_buffer);
897: if (id) {
898: if (verbose)
899: printf("CDID=");
900: printf("%08lx\n", id);
901: }
902: return id ? 0 : 1;
1.1 downsj 903: }
904:
1.35 deraadt 905: /* ARGSUSED */
1.18 deraadt 906: int
1.24 espie 907: info(char *arg)
1.1 downsj 908: {
909: struct ioc_toc_header h;
910: int rc, i, n;
911:
1.18 deraadt 912: rc = ioctl(fd, CDIOREADTOCHEADER, &h);
1.1 downsj 913: if (rc >= 0) {
914: if (verbose)
1.18 deraadt 915: printf("Starting track = %d, ending track = %d, TOC size = %d bytes\n",
916: h.starting_track, h.ending_track, h.len);
1.1 downsj 917: else
1.18 deraadt 918: printf("%d %d %d\n", h.starting_track,
919: h.ending_track, h.len);
1.1 downsj 920: } else {
1.18 deraadt 921: warn("getting toc header");
1.1 downsj 922: return (rc);
923: }
924:
925: n = h.ending_track - h.starting_track + 1;
1.18 deraadt 926: rc = read_toc_entrys((n + 1) * sizeof (struct cd_toc_entry));
1.1 downsj 927: if (rc < 0)
928: return (rc);
929:
930: if (verbose) {
1.18 deraadt 931: printf("track start duration block length type\n");
932: printf("-------------------------------------------------\n");
1.1 downsj 933: }
934:
935: for (i = 0; i < n; i++) {
1.18 deraadt 936: printf("%5d ", toc_buffer[i].track);
1.24 espie 937: prtrack(toc_buffer + i, 0, NULL);
938: }
939: printf("%5d ", toc_buffer[n].track);
940: prtrack(toc_buffer + n, 1, NULL);
941: return (0);
942: }
943:
944: int
945: cddbinfo(char *arg)
946: {
947: struct ioc_toc_header h;
948: int rc, i, n;
949:
950: rc = ioctl(fd, CDIOREADTOCHEADER, &h);
951: if (rc == -1) {
952: warn("getting toc header");
953: return (rc);
954: }
955:
956: n = h.ending_track - h.starting_track + 1;
957: rc = read_toc_entrys((n + 1) * sizeof (struct cd_toc_entry));
958: if (rc < 0)
959: return (rc);
960:
961: if (track_names)
962: free_names(track_names);
963: track_names = NULL;
964:
965: track_names = cddb(cddb_host, n, toc_buffer, arg);
966: if (!track_names)
967: return(0);
968:
969: printf("-------------------------------------------------\n");
970:
971: for (i = 0; i < n; i++) {
972: printf("%5d ", toc_buffer[i].track);
973: prtrack(toc_buffer + i, 0, track_names[i]);
1.1 downsj 974: }
1.18 deraadt 975: printf("%5d ", toc_buffer[n].track);
1.24 espie 976: prtrack(toc_buffer + n, 1, "");
1.1 downsj 977: return (0);
978: }
979:
1.18 deraadt 980: void
1.24 espie 981: lba2msf(unsigned long lba, u_char *m, u_char *s, u_char *f)
1.1 downsj 982: {
1.18 deraadt 983: lba += 150; /* block start offset */
984: lba &= 0xffffff; /* negative lbas use only 24 bits */
1.1 downsj 985: *m = lba / (60 * 75);
986: lba %= (60 * 75);
987: *s = lba / 75;
988: *f = lba % 75;
989: }
990:
1.18 deraadt 991: unsigned int
1.23 espie 992: msf2lba(u_char m, u_char s, u_char f)
1.1 downsj 993: {
994: return (((m * 60) + s) * 75 + f) - 150;
995: }
996:
1.24 espie 997: unsigned long
998: entry2time(struct cd_toc_entry *e)
999: {
1000: int block;
1001: u_char m, s, f;
1002:
1003: if (msf) {
1004: return (e->addr.msf.minute * 60 + e->addr.msf.second);
1005: } else {
1.41 krw 1006: block = e->addr.lba;
1.24 espie 1007: lba2msf(block, &m, &s, &f);
1008: return (m*60+s);
1009: }
1010: }
1011:
1012: unsigned long
1013: entry2frames(struct cd_toc_entry *e)
1014: {
1015: int block;
1016: unsigned char m, s, f;
1017:
1018: if (msf) {
1019: return e->addr.msf.frame + e->addr.msf.second * 75 +
1020: e->addr.msf.minute * 60 * 75;
1021: } else {
1.41 krw 1022: block = e->addr.lba;
1.24 espie 1023: lba2msf(block, &m, &s, &f);
1024: return f + s * 75 + m * 60 * 75;
1025: }
1026: }
1027:
1.18 deraadt 1028: void
1.24 espie 1029: prtrack(struct cd_toc_entry *e, int lastflag, char *name)
1.1 downsj 1030: {
1031: int block, next, len;
1032: u_char m, s, f;
1033:
1034: if (msf) {
1.24 espie 1035: if (!name || lastflag)
1036: /* Print track start */
1037: printf("%2d:%02d.%02d ", e->addr.msf.minute,
1038: e->addr.msf.second, e->addr.msf.frame);
1.1 downsj 1039:
1.18 deraadt 1040: block = msf2lba(e->addr.msf.minute, e->addr.msf.second,
1.1 downsj 1041: e->addr.msf.frame);
1042: } else {
1.41 krw 1043: block = e->addr.lba;
1.24 espie 1044: if (!name || lastflag) {
1045: lba2msf(block, &m, &s, &f);
1046: /* Print track start */
1047: printf("%2d:%02d.%02d ", m, s, f);
1.46 ! krw 1048: }
1.1 downsj 1049: }
1050: if (lastflag) {
1.24 espie 1051: if (!name)
1052: /* Last track -- print block */
1053: printf(" - %6d - -\n", block);
1054: else
1055: printf("\n");
1.1 downsj 1056: return;
1057: }
1058:
1059: if (msf)
1.18 deraadt 1060: next = msf2lba(e[1].addr.msf.minute, e[1].addr.msf.second,
1.1 downsj 1061: e[1].addr.msf.frame);
1062: else
1.41 krw 1063: next = e[1].addr.lba;
1.1 downsj 1064: len = next - block;
1.18 deraadt 1065: lba2msf(len, &m, &s, &f);
1.1 downsj 1066:
1.24 espie 1067: if (name)
1068: printf("%2d:%02d.%02d %s\n", m, s, f, name);
1.1 downsj 1069: /* Print duration, block, length, type */
1.24 espie 1070: else
1071: printf("%2d:%02d.%02d %6d %6d %5s\n", m, s, f, block, len,
1072: (e->control & 4) ? "data" : "audio");
1.1 downsj 1073: }
1074:
1.18 deraadt 1075: int
1.24 espie 1076: play_track(int tstart, int istart, int tend, int iend)
1.1 downsj 1077: {
1078: struct ioc_play_track t;
1079:
1080: t.start_track = tstart;
1081: t.start_index = istart;
1082: t.end_track = tend;
1083: t.end_index = iend;
1084:
1.18 deraadt 1085: return ioctl(fd, CDIOCPLAYTRACKS, &t);
1.1 downsj 1086: }
1087:
1.18 deraadt 1088: int
1.24 espie 1089: play_blocks(int blk, int len)
1.1 downsj 1090: {
1091: struct ioc_play_blocks t;
1092:
1093: t.blk = blk;
1094: t.len = len;
1095:
1.18 deraadt 1096: return ioctl(fd, CDIOCPLAYBLOCKS, &t);
1.1 downsj 1097: }
1098:
1.18 deraadt 1099: int
1.24 espie 1100: setvol(int left, int right)
1.1 downsj 1101: {
1102: struct ioc_vol v;
1103:
1104: v.vol[0] = left;
1105: v.vol[1] = right;
1106: v.vol[2] = 0;
1107: v.vol[3] = 0;
1108:
1.18 deraadt 1109: return ioctl(fd, CDIOCSETVOL, &v);
1.1 downsj 1110: }
1111:
1.18 deraadt 1112: int
1.24 espie 1113: read_toc_entrys(int len)
1.1 downsj 1114: {
1115: struct ioc_read_toc_entry t;
1.11 csapuntz 1116:
1117: if (toc_buffer) {
1.18 deraadt 1118: free(toc_buffer);
1119: toc_buffer = 0;
1.11 csapuntz 1120: }
1121:
1.18 deraadt 1122: toc_buffer = malloc(len);
1.11 csapuntz 1123:
1124: if (!toc_buffer) {
1.18 deraadt 1125: errno = ENOMEM;
1126: return (-1);
1.11 csapuntz 1127: }
1.1 downsj 1128:
1129: t.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT;
1130: t.starting_track = 0;
1131: t.data_len = len;
1132: t.data = toc_buffer;
1133:
1.18 deraadt 1134: return (ioctl(fd, CDIOREADTOCENTRYS, (char *) &t));
1.1 downsj 1135: }
1136:
1.18 deraadt 1137: int
1.24 espie 1138: play_msf(int start_m, int start_s, int start_f, int end_m, int end_s, int end_f)
1.1 downsj 1139: {
1.18 deraadt 1140: struct ioc_play_msf a;
1.1 downsj 1141:
1142: a.start_m = start_m;
1143: a.start_s = start_s;
1144: a.start_f = start_f;
1145: a.end_m = end_m;
1146: a.end_s = end_s;
1147: a.end_f = end_f;
1148:
1.18 deraadt 1149: return ioctl(fd, CDIOCPLAYMSF, (char *) &a);
1.1 downsj 1150: }
1151:
1.21 espie 1152: int
1.24 espie 1153: status(int *trk, int *min, int *sec, int *frame)
1.1 downsj 1154: {
1155: struct ioc_read_subchannel s;
1156: struct cd_sub_channel_info data;
1157: u_char mm, ss, ff;
1158:
1.18 deraadt 1159: bzero(&s, sizeof (s));
1.1 downsj 1160: s.data = &data;
1161: s.data_len = sizeof (data);
1162: s.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT;
1163: s.data_format = CD_CURRENT_POSITION;
1164:
1.18 deraadt 1165: if (ioctl(fd, CDIOCREADSUBCHANNEL, (char *) &s) < 0)
1.1 downsj 1166: return -1;
1167:
1168: *trk = s.data->what.position.track_number;
1169: if (msf) {
1170: *min = s.data->what.position.reladdr.msf.minute;
1171: *sec = s.data->what.position.reladdr.msf.second;
1172: *frame = s.data->what.position.reladdr.msf.frame;
1173: } else {
1.41 krw 1174: /*
1175: * NOTE: CDIOCREADSUBCHANNEL does not put the lba info into
1176: * host order like CDIOREADTOCENTRYS does.
1177: */
1178: lba2msf(betoh32(s.data->what.position.reladdr.lba), &mm, &ss,
1179: &ff);
1.1 downsj 1180: *min = mm;
1181: *sec = ss;
1182: *frame = ff;
1183: }
1184:
1185: return s.data->header.audio_status;
1186: }
1187:
1.18 deraadt 1188: char *
1.24 espie 1189: input(int *cmd)
1.1 downsj 1190: {
1.27 fgsch 1191: char *buf;
1192: int siz = 0;
1.1 downsj 1193: char *p;
1.31 otto 1194: HistEvent hev;
1.1 downsj 1195:
1196: do {
1.27 fgsch 1197: if ((buf = (char *) el_gets(el, &siz)) == NULL || !siz) {
1.1 downsj 1198: *cmd = CMD_QUIT;
1.18 deraadt 1199: fprintf(stderr, "\r\n");
1.1 downsj 1200: return (0);
1201: }
1.27 fgsch 1202: if (strlen(buf) > 1)
1.31 otto 1203: history(hist, &hev, H_ENTER, buf);
1.18 deraadt 1204: p = parse(buf, cmd);
1205: } while (!p);
1.1 downsj 1206: return (p);
1207: }
1208:
1.18 deraadt 1209: char *
1.24 espie 1210: parse(char *buf, int *cmd)
1.1 downsj 1211: {
1212: struct cmdtab *c;
1213: char *p;
1214: int len;
1215:
1.18 deraadt 1216: for (p=buf; isspace(*p); p++)
1.1 downsj 1217: continue;
1218:
1.18 deraadt 1219: if (isdigit(*p) || (p[0] == '#' && isdigit(p[1]))) {
1.1 downsj 1220: *cmd = CMD_PLAY;
1221: return (p);
1222: }
1223:
1.18 deraadt 1224: for (buf = p; *p && ! isspace(*p); p++)
1.1 downsj 1225: continue;
1.46 ! krw 1226:
1.1 downsj 1227: len = p - buf;
1228: if (! len)
1229: return (0);
1230:
1.18 deraadt 1231: if (*p) { /* It must be a spacing character! */
1.1 downsj 1232: char *q;
1233:
1234: *p++ = 0;
1235: for (q=p; *q && *q != '\n' && *q != '\r'; q++)
1236: continue;
1237: *q = 0;
1238: }
1239:
1240: *cmd = -1;
1241: for (c=cmdtab; c->name; ++c) {
1242: /* Is it an exact match? */
1.18 deraadt 1243: if (! strcasecmp(buf, c->name)) {
1.1 downsj 1244: *cmd = c->command;
1245: break;
1.46 ! krw 1246: }
1.1 downsj 1247:
1248: /* Try short hand forms then... */
1.18 deraadt 1249: if (len >= c->min && ! strncasecmp(buf, c->name, len)) {
1.1 downsj 1250: if (*cmd != -1 && *cmd != c->command) {
1.18 deraadt 1251: fprintf(stderr, "Ambiguous command\n");
1.1 downsj 1252: return (0);
1253: }
1254: *cmd = c->command;
1.46 ! krw 1255: }
1.1 downsj 1256: }
1257:
1258: if (*cmd == -1) {
1.18 deraadt 1259: fprintf(stderr, "%s: Invalid command, enter ``help'' for commands.\n",
1260: __progname);
1.1 downsj 1261: return (0);
1262: }
1263:
1.18 deraadt 1264: while (isspace(*p))
1.1 downsj 1265: p++;
1266: return p;
1267: }
1268:
1.18 deraadt 1269: int
1.24 espie 1270: open_cd(char *dev)
1.1 downsj 1271: {
1.9 millert 1272: char *realdev;
1.12 millert 1273: int tries;
1.1 downsj 1274:
1275: if (fd > -1)
1276: return (1);
1277:
1.12 millert 1278: for (tries = 0; fd < 0 && tries < 10; tries++) {
1279: fd = opendev(dev, O_RDONLY, OPENDEV_PART, &realdev);
1280: if (fd < 0) {
1281: if (errno == ENXIO) {
1282: /* ENXIO has an overloaded meaning here.
1283: * The original "Device not configured" should
1284: * be interpreted as "No disc in drive %s". */
1.18 deraadt 1285: warnx("No disc in drive %s.", realdev);
1.12 millert 1286: return (0);
1287: } else if (errno != EIO) {
1288: /* EIO may simply mean the device is not ready
1289: * yet which is common with CD changers. */
1.18 deraadt 1290: warn("Can't open %s", realdev);
1.12 millert 1291: return (0);
1292: }
1293: }
1.18 deraadt 1294: sleep(1);
1.12 millert 1295: }
1.1 downsj 1296: if (fd < 0) {
1.18 deraadt 1297: warn("Can't open %s", realdev);
1.9 millert 1298: return (0);
1.1 downsj 1299: }
1300: return (1);
1.27 fgsch 1301: }
1302:
1303: char *
1304: prompt(void)
1305: {
1306: return (verbose ? "cdio> " : "");
1307: }
1308:
1309: void
1310: switch_el(void)
1311: {
1.31 otto 1312: HistEvent hev;
1313:
1.27 fgsch 1314: if (el == NULL && hist == NULL) {
1.31 otto 1315: el = el_init(__progname, stdin, stdout, stderr);
1.27 fgsch 1316: hist = history_init();
1.31 otto 1317: history(hist, &hev, H_SETSIZE, 100);
1.27 fgsch 1318: el_set(el, EL_HIST, history, hist);
1319: el_set(el, EL_EDITOR, "emacs");
1320: el_set(el, EL_PROMPT, prompt);
1321: el_set(el, EL_SIGNAL, 1);
1322: el_source(el, NULL);
1323:
1324: } else {
1325: if (hist != NULL) {
1326: history_end(hist);
1327: hist = NULL;
1328: }
1329: if (el != NULL) {
1330: el_end(el);
1331: el = NULL;
1332: }
1333: }
1.42 krw 1334: }
1335:
1336: void
1337: addmsf(u_int *m, u_int *s, u_int *f, u_char m_inc, u_char s_inc, u_char f_inc)
1338: {
1339: *f += f_inc;
1340: if (*f > 75) {
1341: *s += *f / 75;
1342: *f %= 75;
1343: }
1344:
1345: *s += s_inc;
1346: if (*s > 60) {
1347: *m += *s / 60;
1348: *s %= 60;
1349: }
1350:
1351: *m += m_inc;
1.44 krw 1352: }
1353:
1354: int
1355: cmpmsf(u_char m1, u_char s1, u_char f1, u_char m2, u_char s2, u_char f2)
1356: {
1357: if (m1 > m2)
1358: return (1);
1359: else if (m1 < m2)
1360: return (-1);
1361:
1362: if (s1 > s2)
1363: return (1);
1364: else if (s1 < s2)
1365: return (-1);
1366:
1367: if (f1 > f2)
1368: return (1);
1369: else if (f1 < f2)
1370: return (-1);
1371:
1372: return (0);
1.43 krw 1373: }
1374:
1375: void
1376: toc2msf(u_int track, u_char *m, u_char *s, u_char *f)
1377: {
1378: struct cd_toc_entry *ctep;
1379:
1380: ctep = &toc_buffer[track - 1];
1381:
1382: if (msf) {
1383: *m = ctep->addr.msf.minute;
1384: *s = ctep->addr.msf.second;
1385: *f = ctep->addr.msf.frame;
1386: } else
1387: lba2msf(ctep->addr.lba, m, s, f);
1.1 downsj 1388: }