cdcontrol.c revision 77168
110099Sjkh/* 213884Sache * Compact Disc Control Utility by Serge V. Vakulenko <vak@cronyx.ru>. 310099Sjkh * Based on the non-X based CD player by Jean-Marc Zucconi and 413832Sache * Andrey A. Chernov. 513884Sache * 613985Sache * Fixed and further modified on 5-Sep-1995 by Jukka Ukkonen <jau@funet.fi>. 713985Sache * 813985Sache * 11-Sep-1995: Jukka A. Ukkonen <jau@funet.fi> 913985Sache * A couple of further fixes to my own earlier "fixes". 1013985Sache * 1113985Sache * 18-Sep-1995: Jukka A. Ukkonen <jau@funet.fi> 1213985Sache * Added an ability to specify addresses relative to the 1313985Sache * beginning of a track. This is in fact a variation of 1413985Sache * doing the simple play_msf() call. 1513985Sache * 1613985Sache * 11-Oct-1995: Serge V.Vakulenko <vak@cronyx.ru> 1713985Sache * New eject algorithm. 1813985Sache * Some code style reformatting. 1910099Sjkh */ 2013985Sache 2129103Scharnier#ifndef lint 2229103Scharnierstatic const char rcsid[] = 2350479Speter "$FreeBSD: head/usr.sbin/cdcontrol/cdcontrol.c 77168 2001-05-25 09:24:50Z kris $"; 2429103Scharnier#endif /* not lint */ 2529103Scharnier 2677168Skris#include <sys/cdio.h> 2777168Skris#include <sys/file.h> 2877168Skris#include <sys/ioctl.h> 2977168Skris#include <sys/param.h> 3013985Sache#include <ctype.h> 3129103Scharnier#include <err.h> 3229103Scharnier#include <errno.h> 3377168Skris#include <histedit.h> 3469793Sobrien#include <paths.h> 3510099Sjkh#include <stdio.h> 3610099Sjkh#include <stdlib.h> 3710099Sjkh#include <string.h> 3810099Sjkh#include <unistd.h> 3977168Skris#include <vis.h> 4010099Sjkh 4113884Sache#define VERSION "2.0" 4210099Sjkh 4313985Sache#define ASTS_INVALID 0x00 /* Audio status byte not valid */ 4413985Sache#define ASTS_PLAYING 0x11 /* Audio play operation in progress */ 4513985Sache#define ASTS_PAUSED 0x12 /* Audio play operation paused */ 4613985Sache#define ASTS_COMPLETED 0x13 /* Audio play operation successfully completed */ 4713985Sache#define ASTS_ERROR 0x14 /* Audio play operation stopped due to error */ 4813985Sache#define ASTS_VOID 0x15 /* No current audio status to return */ 4910099Sjkh 5013985Sache#ifndef DEFAULT_CD_DRIVE 5113985Sache# define DEFAULT_CD_DRIVE "/dev/cd0c" 5213985Sache#endif 5313985Sache 5413985Sache#ifndef DEFAULT_CD_PARTITION 5513985Sache# define DEFAULT_CD_PARTITION "c" 5613985Sache#endif 5713985Sache 5813985Sache#define CMD_DEBUG 1 5913985Sache#define CMD_EJECT 2 6013985Sache#define CMD_HELP 3 6113985Sache#define CMD_INFO 4 6213985Sache#define CMD_PAUSE 5 6313985Sache#define CMD_PLAY 6 6413985Sache#define CMD_QUIT 7 6513985Sache#define CMD_RESUME 8 6613985Sache#define CMD_STOP 9 6713985Sache#define CMD_VOLUME 10 6813985Sache#define CMD_CLOSE 11 6913985Sache#define CMD_RESET 12 7013985Sache#define CMD_SET 13 7113985Sache#define CMD_STATUS 14 7263091Sjoe#define CMD_CDID 15 7377168Skris#define CMD_NEXT 16 7477168Skris#define CMD_PREVIOUS 17 7532782Sjmz#define STATUS_AUDIO 0x1 7632782Sjmz#define STATUS_MEDIA 0x2 7732782Sjmz#define STATUS_VOLUME 0x4 7813985Sache 7910099Sjkhstruct cmdtab { 8010099Sjkh int command; 8110099Sjkh char *name; 8213985Sache unsigned min; 8310099Sjkh char *args; 8410099Sjkh} cmdtab[] = { 8513985Sache{ CMD_CLOSE, "close", 1, "" }, 8613985Sache{ CMD_DEBUG, "debug", 1, "on | off" }, 8713985Sache{ CMD_EJECT, "eject", 1, "" }, 8813985Sache{ CMD_HELP, "?", 1, 0 }, 8913985Sache{ CMD_HELP, "help", 1, "" }, 9013985Sache{ CMD_INFO, "info", 1, "" }, 9177168Skris{ CMD_NEXT, "next", 1, "" }, 9213985Sache{ CMD_PAUSE, "pause", 2, "" }, 9313985Sache{ CMD_PLAY, "play", 1, "min1:sec1[.fram1] [min2:sec2[.fram2]]" }, 9413985Sache{ CMD_PLAY, "play", 1, "track1[.index1] [track2[.index2]]" }, 9513985Sache{ CMD_PLAY, "play", 1, "tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]]" }, 9613985Sache{ CMD_PLAY, "play", 1, "[#block [len]]" }, 9777168Skris{ CMD_PREVIOUS, "previous", 2, "" }, 9813985Sache{ CMD_QUIT, "quit", 1, "" }, 9913985Sache{ CMD_RESET, "reset", 4, "" }, 10013985Sache{ CMD_RESUME, "resume", 1, "" }, 10113985Sache{ CMD_SET, "set", 2, "msf | lba" }, 10232782Sjmz{ CMD_STATUS, "status", 1, "[audio | media | volume]" }, 10313985Sache{ CMD_STOP, "stop", 3, "" }, 10413985Sache{ CMD_VOLUME, "volume", 1, "<l> <r> | left | right | mute | mono | stereo" }, 10563091Sjoe{ CMD_CDID, "cdid", 2, "" }, 10613985Sache{ 0, } 10710099Sjkh}; 10810099Sjkh 10913985Sachestruct cd_toc_entry toc_buffer[100]; 11010099Sjkh 11113985Sacheconst char *cdname; 11213985Sacheint fd = -1; 11313985Sacheint verbose = 1; 11413985Sacheint msf = 1; 11510099Sjkh 11613985Sacheint setvol __P((int, int)); 11713985Sacheint read_toc_entrys __P((int)); 11813985Sacheint play_msf __P((int, int, int, int, int, int)); 11913985Sacheint play_track __P((int, int, int, int)); 12013985Sacheint get_vol __P((int *, int *)); 12113985Sacheint status __P((int *, int *, int *, int *)); 12213985Sacheint open_cd __P((void)); 12377168Skrisint next_prev __P((char *arg, int)); 12413985Sacheint play __P((char *arg)); 12513985Sacheint info __P((char *arg)); 12663091Sjoeint cdid __P((void)); 12713985Sacheint pstatus __P((char *arg)); 12813985Sachechar *input __P((int *)); 12913985Sachevoid prtrack __P((struct cd_toc_entry *e, int lastflag)); 13013985Sachevoid lba2msf __P((unsigned long lba, 13113985Sache u_char *m, u_char *s, u_char *f)); 13213985Sacheunsigned int msf2lba __P((u_char m, u_char s, u_char f)); 13313985Sacheint play_blocks __P((int blk, int len)); 13413985Sacheint run __P((int cmd, char *arg)); 13513985Sachechar *parse __P((char *buf, int *cmd)); 13610099Sjkh 13710099Sjkhvoid help () 13810099Sjkh{ 13910099Sjkh struct cmdtab *c; 14013985Sache char *s, n; 14113985Sache int i; 14210099Sjkh 14310099Sjkh for (c=cmdtab; c->name; ++c) { 14410099Sjkh if (! c->args) 14510099Sjkh continue; 14613985Sache printf("\t"); 14713985Sache for (i = c->min, s = c->name; *s; s++, i--) { 14813985Sache if (i > 0) 14913985Sache n = toupper(*s); 15013985Sache else 15113985Sache n = *s; 15213985Sache putchar(n); 15313985Sache } 15410099Sjkh if (*c->args) 15510099Sjkh printf (" %s", c->args); 15610099Sjkh printf ("\n"); 15710099Sjkh } 15813985Sache printf ("\n\tThe word \"play\" is not required for the play commands.\n"); 15913985Sache printf ("\tThe plain target address is taken as a synonym for play.\n"); 16010099Sjkh} 16110099Sjkh 16210099Sjkhvoid usage () 16310099Sjkh{ 16443479Sbillf fprintf (stderr, "usage: cdcontrol [-sv] [-f device] [command ...]\n"); 16510099Sjkh exit (1); 16610099Sjkh} 16710099Sjkh 16871122Sjoechar *use_cdrom_instead(char *old_envvar) 16971122Sjoe{ 17071122Sjoe char *device; 17171122Sjoe 17271122Sjoe device = getenv(old_envvar); 17371122Sjoe if (device) 17471122Sjoe warnx("%s environment variable deprecated, " 17571122Sjoe "please use CDROM in the future.", old_envvar); 17671122Sjoe return device; 17771122Sjoe} 17871122Sjoe 17971122Sjoe 18010099Sjkhint main (int argc, char **argv) 18110099Sjkh{ 18210099Sjkh int cmd; 18310099Sjkh char *arg; 18410099Sjkh 18510099Sjkh for (;;) { 18610099Sjkh switch (getopt (argc, argv, "svhf:")) { 18710099Sjkh case EOF: 18810099Sjkh break; 18910099Sjkh case 's': 19010099Sjkh verbose = 0; 19110099Sjkh continue; 19210099Sjkh case 'v': 19310099Sjkh verbose = 2; 19410099Sjkh continue; 19510099Sjkh case 'f': 19610099Sjkh cdname = optarg; 19710099Sjkh continue; 19810099Sjkh case 'h': 19910099Sjkh default: 20010099Sjkh usage (); 20110099Sjkh } 20210099Sjkh break; 20310099Sjkh } 20410099Sjkh argc -= optind; 20510099Sjkh argv += optind; 20610099Sjkh 20713985Sache if (argc > 0 && ! strcasecmp (*argv, "help")) 20810099Sjkh usage (); 20910099Sjkh 21010099Sjkh if (! cdname) { 21170149Sdes cdname = getenv("CDROM"); 21270149Sdes } 21370149Sdes 21475324Sjoe if (! cdname) 21575324Sjoe cdname = use_cdrom_instead("MUSIC_CD"); 21675324Sjoe if (! cdname) 21775324Sjoe cdname = use_cdrom_instead("CD_DRIVE"); 21875324Sjoe if (! cdname) 21975324Sjoe cdname = use_cdrom_instead("DISC"); 22075324Sjoe if (! cdname) 22175324Sjoe cdname = use_cdrom_instead("CDPLAY"); 22275324Sjoe 22370149Sdes if (! cdname) { 22413985Sache cdname = DEFAULT_CD_DRIVE; 22529103Scharnier warnx("no CD device name specified, defaulting to %s", cdname); 22610099Sjkh } 22710099Sjkh 22810099Sjkh if (argc > 0) { 22910099Sjkh char buf[80], *p; 23010099Sjkh int len; 23110099Sjkh 23213985Sache for (p=buf; argc-->0; ++argv) { 23310099Sjkh len = strlen (*argv); 23413985Sache 23510099Sjkh if (p + len >= buf + sizeof (buf) - 1) 23610099Sjkh usage (); 23713985Sache 23810099Sjkh if (p > buf) 23910099Sjkh *p++ = ' '; 24013985Sache 24110099Sjkh strcpy (p, *argv); 24210099Sjkh p += len; 24310099Sjkh } 24410099Sjkh *p = 0; 24510099Sjkh arg = parse (buf, &cmd); 24613985Sache return (run (cmd, arg)); 24710099Sjkh } 24810099Sjkh 24910099Sjkh if (verbose == 1) 25010099Sjkh verbose = isatty (0); 25113985Sache 25210099Sjkh if (verbose) { 25313985Sache printf ("Compact Disc Control utility, version %s\n", VERSION); 25410099Sjkh printf ("Type `?' for command list\n\n"); 25510099Sjkh } 25610099Sjkh 25710099Sjkh for (;;) { 25810099Sjkh arg = input (&cmd); 25910099Sjkh if (run (cmd, arg) < 0) { 26010099Sjkh if (verbose) 26129103Scharnier warn(NULL); 26210099Sjkh close (fd); 26310099Sjkh fd = -1; 26410099Sjkh } 26510099Sjkh fflush (stdout); 26610099Sjkh } 26710099Sjkh} 26810099Sjkh 26910099Sjkhint run (int cmd, char *arg) 27010099Sjkh{ 27110099Sjkh int l, r, rc; 27210099Sjkh 27310099Sjkh switch (cmd) { 27413985Sache 27510099Sjkh case CMD_QUIT: 27610099Sjkh exit (0); 27710099Sjkh 27813985Sache case CMD_INFO: 27913985Sache if (fd < 0 && ! open_cd ()) 28013985Sache return (0); 28110099Sjkh 28210099Sjkh return info (arg); 28310099Sjkh 28463091Sjoe case CMD_CDID: 28563091Sjoe if (fd < 0 && ! open_cd ()) 28663091Sjoe return (0); 28763091Sjoe 28863091Sjoe return cdid (); 28963091Sjoe 29013884Sache case CMD_STATUS: 29113985Sache if (fd < 0 && ! open_cd ()) 29213985Sache return (0); 29313985Sache 29413884Sache return pstatus (arg); 29513884Sache 29677168Skris case CMD_NEXT: 29777168Skris case CMD_PREVIOUS: 29877168Skris if (fd < 0 && ! open_cd ()) 29977168Skris return (0); 30077168Skris 30177168Skris while (isspace (*arg)) 30277168Skris arg++; 30377168Skris 30477168Skris return next_prev (arg, cmd); 30577168Skris 30610099Sjkh case CMD_PAUSE: 30713985Sache if (fd < 0 && ! open_cd ()) 30813985Sache return (0); 30913985Sache 31010099Sjkh return ioctl (fd, CDIOCPAUSE); 31110099Sjkh 31210099Sjkh case CMD_RESUME: 31313985Sache if (fd < 0 && ! open_cd ()) 31413985Sache return (0); 31513985Sache 31610099Sjkh return ioctl (fd, CDIOCRESUME); 31710099Sjkh 31810099Sjkh case CMD_STOP: 31913985Sache if (fd < 0 && ! open_cd ()) 32013985Sache return (0); 32110099Sjkh 32213985Sache rc = ioctl (fd, CDIOCSTOP); 32313985Sache 32413985Sache (void) ioctl (fd, CDIOCALLOW); 32513985Sache 32613985Sache return (rc); 32713985Sache 32813884Sache case CMD_RESET: 32913985Sache if (fd < 0 && ! open_cd ()) 33013985Sache return (0); 33113985Sache 33213884Sache rc = ioctl (fd, CDIOCRESET); 33313884Sache if (rc < 0) 33413884Sache return rc; 33513884Sache close(fd); 33613884Sache fd = -1; 33713884Sache return (0); 33813884Sache 33910099Sjkh case CMD_DEBUG: 34013985Sache if (fd < 0 && ! open_cd ()) 34113985Sache return (0); 34213985Sache 34313985Sache if (! strcasecmp (arg, "on")) 34410099Sjkh return ioctl (fd, CDIOCSETDEBUG); 34513985Sache 34613985Sache if (! strcasecmp (arg, "off")) 34710099Sjkh return ioctl (fd, CDIOCCLRDEBUG); 34813985Sache 34929103Scharnier warnx("invalid command arguments"); 35013985Sache 35110099Sjkh return (0); 35210099Sjkh 35310099Sjkh case CMD_EJECT: 35413985Sache if (fd < 0 && ! open_cd ()) 35513985Sache return (0); 35613985Sache 35710099Sjkh (void) ioctl (fd, CDIOCALLOW); 35810099Sjkh rc = ioctl (fd, CDIOCEJECT); 35910099Sjkh if (rc < 0) 36010099Sjkh return (rc); 36113865Sache return (0); 36213865Sache 36313985Sache case CMD_CLOSE: 36413985Sache if (fd < 0 && ! open_cd ()) 36513985Sache return (0); 36613985Sache 36713985Sache (void) ioctl (fd, CDIOCALLOW); 36813865Sache rc = ioctl (fd, CDIOCCLOSE); 36913865Sache if (rc < 0) 37013865Sache return (rc); 37113865Sache close(fd); 37210099Sjkh fd = -1; 37310099Sjkh return (0); 37410099Sjkh 37510099Sjkh case CMD_PLAY: 37613985Sache if (fd < 0 && ! open_cd ()) 37713985Sache return (0); 37813985Sache 37913985Sache while (isspace (*arg)) 38013985Sache arg++; 38113985Sache 38210099Sjkh return play (arg); 38310099Sjkh 38413884Sache case CMD_SET: 38513985Sache if (! strcasecmp (arg, "msf")) 38613884Sache msf = 1; 38713985Sache else if (! strcasecmp (arg, "lba")) 38813884Sache msf = 0; 38913884Sache else 39029103Scharnier warnx("invalid command arguments"); 39113884Sache return (0); 39213884Sache 39310099Sjkh case CMD_VOLUME: 39413985Sache if (fd < 0 && !open_cd ()) 39513985Sache return (0); 39610099Sjkh 39713985Sache if (! strncasecmp (arg, "left", strlen(arg))) 39810099Sjkh return ioctl (fd, CDIOCSETLEFT); 39913985Sache 40013985Sache if (! strncasecmp (arg, "right", strlen(arg))) 40110099Sjkh return ioctl (fd, CDIOCSETRIGHT); 40213985Sache 40313985Sache if (! strncasecmp (arg, "mono", strlen(arg))) 40410099Sjkh return ioctl (fd, CDIOCSETMONO); 40513985Sache 40613985Sache if (! strncasecmp (arg, "stereo", strlen(arg))) 40710099Sjkh return ioctl (fd, CDIOCSETSTERIO); 40810099Sjkh 40913985Sache if (! strncasecmp (arg, "mute", strlen(arg))) 41013985Sache return ioctl (fd, CDIOCSETMUTE); 41113985Sache 41210099Sjkh if (2 != sscanf (arg, "%d %d", &l, &r)) { 41329103Scharnier warnx("invalid command arguments"); 41410099Sjkh return (0); 41510099Sjkh } 41613985Sache 41710099Sjkh return setvol (l, r); 41813985Sache 41913985Sache default: 42013985Sache case CMD_HELP: 42113985Sache help (); 42213985Sache return (0); 42313985Sache 42410099Sjkh } 42510099Sjkh} 42610099Sjkh 42710099Sjkhint play (char *arg) 42810099Sjkh{ 42910099Sjkh struct ioc_toc_header h; 43010099Sjkh int rc, n, start, end = 0, istart = 1, iend = 1; 43110099Sjkh 43210099Sjkh rc = ioctl (fd, CDIOREADTOCHEADER, &h); 43313985Sache 43410099Sjkh if (rc < 0) 43510099Sjkh return (rc); 43610099Sjkh 43710099Sjkh n = h.ending_track - h.starting_track + 1; 43810099Sjkh rc = read_toc_entrys ((n + 1) * sizeof (struct cd_toc_entry)); 43913985Sache 44010099Sjkh if (rc < 0) 44110099Sjkh return (rc); 44210099Sjkh 44313989Sache if (! arg || ! *arg) { 44413985Sache /* Play the whole disc */ 44513989Sache if (msf) 44613989Sache return play_blocks (0, msf2lba (toc_buffer[n].addr.msf.minute, 44713989Sache toc_buffer[n].addr.msf.second, 44813989Sache toc_buffer[n].addr.msf.frame)); 44913989Sache else 45013989Sache return play_blocks (0, ntohl(toc_buffer[n].addr.lba)); 45113989Sache } 45210099Sjkh 45310099Sjkh if (strchr (arg, '#')) { 45413985Sache /* Play block #blk [ len ] */ 45510099Sjkh int blk, len = 0; 45610099Sjkh 45710099Sjkh if (2 != sscanf (arg, "#%d%d", &blk, &len) && 45813985Sache 1 != sscanf (arg, "#%d", &blk)) 45913985Sache goto Clean_up; 46013985Sache 46113989Sache if (len == 0) { 46213989Sache if (msf) 46313989Sache len = msf2lba (toc_buffer[n].addr.msf.minute, 46413989Sache toc_buffer[n].addr.msf.second, 46513989Sache toc_buffer[n].addr.msf.frame) - blk; 46613989Sache else 46713989Sache len = ntohl(toc_buffer[n].addr.lba) - blk; 46813989Sache } 46910099Sjkh return play_blocks (blk, len); 47010099Sjkh } 47110099Sjkh 47210099Sjkh if (strchr (arg, ':')) { 47310099Sjkh /* 47410099Sjkh * Play MSF m1:s1 [ .f1 ] [ m2:s2 [ .f2 ] ] 47513985Sache * 47613985Sache * Will now also undestand timed addresses relative 47713985Sache * to the beginning of a track in the form... 47813985Sache * 47913985Sache * tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]] 48010099Sjkh */ 48113985Sache unsigned tr1, tr2; 48213985Sache unsigned m1, m2, s1, s2, f1, f2; 48313989Sache unsigned char tm, ts, tf; 48410099Sjkh 48513985Sache tr2 = m2 = s2 = f2 = f1 = 0; 48613985Sache if (8 == sscanf (arg, "%d %d:%d.%d %d %d:%d.%d", 48713985Sache &tr1, &m1, &s1, &f1, &tr2, &m2, &s2, &f2)) 48813985Sache goto Play_Relative_Addresses; 48913985Sache 49013985Sache tr2 = m2 = s2 = f2 = f1 = 0; 49113985Sache if (7 == sscanf (arg, "%d %d:%d %d %d:%d.%d", 49213985Sache &tr1, &m1, &s1, &tr2, &m2, &s2, &f2)) 49313985Sache goto Play_Relative_Addresses; 49413985Sache 49513985Sache tr2 = m2 = s2 = f2 = f1 = 0; 49613985Sache if (7 == sscanf (arg, "%d %d:%d.%d %d %d:%d", 49713985Sache &tr1, &m1, &s1, &f1, &tr2, &m2, &s2)) 49813985Sache goto Play_Relative_Addresses; 49913985Sache 50013985Sache tr2 = m2 = s2 = f2 = f1 = 0; 50113985Sache if (7 == sscanf (arg, "%d %d:%d.%d %d:%d.%d", 50213985Sache &tr1, &m1, &s1, &f1, &m2, &s2, &f2)) 50313985Sache goto Play_Relative_Addresses; 50413985Sache 50513985Sache tr2 = m2 = s2 = f2 = f1 = 0; 50613985Sache if (6 == sscanf (arg, "%d %d:%d.%d %d:%d", 50713985Sache &tr1, &m1, &s1, &f1, &m2, &s2)) 50813985Sache goto Play_Relative_Addresses; 50913985Sache 51013985Sache tr2 = m2 = s2 = f2 = f1 = 0; 51113985Sache if (6 == sscanf (arg, "%d %d:%d %d:%d.%d", 51213985Sache &tr1, &m1, &s1, &m2, &s2, &f2)) 51313985Sache goto Play_Relative_Addresses; 51413985Sache 51513985Sache tr2 = m2 = s2 = f2 = f1 = 0; 51613985Sache if (6 == sscanf (arg, "%d %d:%d.%d %d %d", 51713985Sache &tr1, &m1, &s1, &f1, &tr2, &m2)) 51813985Sache goto Play_Relative_Addresses; 51913985Sache 52013985Sache tr2 = m2 = s2 = f2 = f1 = 0; 52113985Sache if (5 == sscanf (arg, "%d %d:%d %d:%d", &tr1, &m1, &s1, &m2, &s2)) 52213985Sache goto Play_Relative_Addresses; 52313985Sache 52413985Sache tr2 = m2 = s2 = f2 = f1 = 0; 52513985Sache if (5 == sscanf (arg, "%d %d:%d %d %d", 52613985Sache &tr1, &m1, &s1, &tr2, &m2)) 52713985Sache goto Play_Relative_Addresses; 52813985Sache 52913985Sache tr2 = m2 = s2 = f2 = f1 = 0; 53013985Sache if (5 == sscanf (arg, "%d %d:%d.%d %d", 53113985Sache &tr1, &m1, &s1, &f1, &tr2)) 53213985Sache goto Play_Relative_Addresses; 53313985Sache 53413985Sache tr2 = m2 = s2 = f2 = f1 = 0; 53513985Sache if (4 == sscanf (arg, "%d %d:%d %d", &tr1, &m1, &s1, &tr2)) 53613985Sache goto Play_Relative_Addresses; 53713985Sache 53813985Sache tr2 = m2 = s2 = f2 = f1 = 0; 53913985Sache if (4 == sscanf (arg, "%d %d:%d.%d", &tr1, &m1, &s1, &f1)) 54013985Sache goto Play_Relative_Addresses; 54113985Sache 54213985Sache tr2 = m2 = s2 = f2 = f1 = 0; 54313985Sache if (3 == sscanf (arg, "%d %d:%d", &tr1, &m1, &s1)) 54413985Sache goto Play_Relative_Addresses; 54513985Sache 54613985Sache tr2 = m2 = s2 = f2 = f1 = 0; 54713985Sache goto Try_Absolute_Timed_Addresses; 54813985Sache 54913985SachePlay_Relative_Addresses: 55013985Sache if (! tr1) 55113985Sache tr1 = 1; 55213985Sache else if (tr1 > n) 55313985Sache tr1 = n; 55413985Sache 55513989Sache if (msf) { 55613989Sache tm = toc_buffer[tr1].addr.msf.minute; 55713989Sache ts = toc_buffer[tr1].addr.msf.second; 55813989Sache tf = toc_buffer[tr1].addr.msf.frame; 55913989Sache } else 56013989Sache lba2msf(ntohl(toc_buffer[tr1].addr.lba), 56113989Sache &tm, &ts, &tf); 56213989Sache if ((m1 > tm) 56313989Sache || ((m1 == tm) 56413989Sache && ((s1 > ts) 56513989Sache || ((s1 == ts) 56613989Sache && (f1 > tf))))) { 56713985Sache printf ("Track %d is not that long.\n", tr1); 56813985Sache return (0); 56913985Sache } 57013985Sache 57113985Sache tr1--; 57213985Sache 57313989Sache f1 += tf; 57413985Sache if (f1 >= 75) { 57513985Sache s1 += f1 / 75; 57613985Sache f1 %= 75; 57713985Sache } 57813985Sache 57913989Sache s1 += ts; 58013985Sache if (s1 >= 60) { 58113985Sache m1 += s1 / 60; 58213985Sache s1 %= 60; 58313985Sache } 58413985Sache 58513989Sache m1 += tm; 58613985Sache 58713985Sache if (! tr2) { 58813985Sache if (m2 || s2 || f2) { 58913985Sache tr2 = tr1; 59013985Sache f2 += f1; 59113985Sache if (f2 >= 75) { 59213985Sache s2 += f2 / 75; 59313985Sache f2 %= 75; 59413985Sache } 59513985Sache 59613985Sache s2 += s1; 59713985Sache if (s2 > 60) { 59813985Sache m2 += s2 / 60; 59913985Sache s2 %= 60; 60013985Sache } 60113985Sache 60213985Sache m2 += m1; 60313985Sache } else { 60413985Sache tr2 = n; 60513989Sache if (msf) { 60613989Sache m2 = toc_buffer[n].addr.msf.minute; 60713989Sache s2 = toc_buffer[n].addr.msf.second; 60813989Sache f2 = toc_buffer[n].addr.msf.frame; 60913989Sache } else { 61013989Sache lba2msf(ntohl(toc_buffer[n].addr.lba), 61113989Sache &tm, &ts, &tf); 61213989Sache m2 = tm; 61313989Sache s2 = ts; 61413989Sache f2 = tf; 61513989Sache } 61613985Sache } 61713985Sache } else if (tr2 > n) { 61813985Sache tr2 = n; 61913985Sache m2 = s2 = f2 = 0; 62013985Sache } else { 62113985Sache if (m2 || s2 || f2) 62213985Sache tr2--; 62313989Sache if (msf) { 62413989Sache tm = toc_buffer[tr2].addr.msf.minute; 62513989Sache ts = toc_buffer[tr2].addr.msf.second; 62613989Sache tf = toc_buffer[tr2].addr.msf.frame; 62713989Sache } else 62813989Sache lba2msf(ntohl(toc_buffer[tr2].addr.lba), 62913989Sache &tm, &ts, &tf); 63013989Sache f2 += tf; 63113985Sache if (f2 >= 75) { 63213985Sache s2 += f2 / 75; 63313985Sache f2 %= 75; 63413985Sache } 63513985Sache 63613989Sache s2 += ts; 63713985Sache if (s2 > 60) { 63813985Sache m2 += s2 / 60; 63913985Sache s2 %= 60; 64013985Sache } 64113985Sache 64213989Sache m2 += tm; 64313985Sache } 64413985Sache 64513989Sache if (msf) { 64613989Sache tm = toc_buffer[n].addr.msf.minute; 64713989Sache ts = toc_buffer[n].addr.msf.second; 64813989Sache tf = toc_buffer[n].addr.msf.frame; 64913989Sache } else 65013989Sache lba2msf(ntohl(toc_buffer[n].addr.lba), 65113989Sache &tm, &ts, &tf); 65213985Sache if ((tr2 < n) 65313989Sache && ((m2 > tm) 65413989Sache || ((m2 == tm) 65513989Sache && ((s2 > ts) 65613989Sache || ((s2 == ts) 65713989Sache && (f2 > tf)))))) { 65813985Sache printf ("The playing time of the disc is not that long.\n"); 65913985Sache return (0); 66013985Sache } 66113985Sache return (play_msf (m1, s1, f1, m2, s2, f2)); 66213985Sache 66313985SacheTry_Absolute_Timed_Addresses: 66413985Sache if (6 != sscanf (arg, "%d:%d.%d%d:%d.%d", 66513985Sache &m1, &s1, &f1, &m2, &s2, &f2) && 66610099Sjkh 5 != sscanf (arg, "%d:%d.%d%d:%d", &m1, &s1, &f1, &m2, &s2) && 66710099Sjkh 5 != sscanf (arg, "%d:%d%d:%d.%d", &m1, &s1, &m2, &s2, &f2) && 66810099Sjkh 3 != sscanf (arg, "%d:%d.%d", &m1, &s1, &f1) && 66910099Sjkh 4 != sscanf (arg, "%d:%d%d:%d", &m1, &s1, &m2, &s2) && 67010099Sjkh 2 != sscanf (arg, "%d:%d", &m1, &s1)) 67113985Sache goto Clean_up; 67213985Sache 67310099Sjkh if (m2 == 0) { 67413989Sache if (msf) { 67513989Sache m2 = toc_buffer[n].addr.msf.minute; 67613989Sache s2 = toc_buffer[n].addr.msf.second; 67713989Sache f2 = toc_buffer[n].addr.msf.frame; 67813989Sache } else { 67913989Sache lba2msf(ntohl(toc_buffer[n].addr.lba), 68013989Sache &tm, &ts, &tf); 68113989Sache m2 = tm; 68213989Sache s2 = ts; 68313989Sache f2 = tf; 68413989Sache } 68510099Sjkh } 68610099Sjkh return play_msf (m1, s1, f1, m2, s2, f2); 68710099Sjkh } 68810099Sjkh 68910099Sjkh /* 69010099Sjkh * Play track trk1 [ .idx1 ] [ trk2 [ .idx2 ] ] 69110099Sjkh */ 69210099Sjkh if (4 != sscanf (arg, "%d.%d%d.%d", &start, &istart, &end, &iend) && 69310099Sjkh 3 != sscanf (arg, "%d.%d%d", &start, &istart, &end) && 69410099Sjkh 3 != sscanf (arg, "%d%d.%d", &start, &end, &iend) && 69510099Sjkh 2 != sscanf (arg, "%d.%d", &start, &istart) && 69610099Sjkh 2 != sscanf (arg, "%d%d", &start, &end) && 69710099Sjkh 1 != sscanf (arg, "%d", &start)) 69813985Sache goto Clean_up; 69913985Sache 70010099Sjkh if (end == 0) 70110099Sjkh end = n; 70213985Sache return (play_track (start, istart, end, iend)); 70313985Sache 70413985SacheClean_up: 70529103Scharnier warnx("invalid command arguments"); 70613985Sache return (0); 70710099Sjkh} 70810099Sjkh 70977168Skrisint next_prev (char *arg, int cmd) 71077168Skris{ 71177168Skris struct ioc_toc_header h; 71277168Skris int dir, junk, n, off, rc, trk; 71377168Skris 71477168Skris dir = (cmd == CMD_NEXT) ? 1 : -1; 71577168Skris rc = ioctl (fd, CDIOREADTOCHEADER, &h); 71677168Skris if (rc < 0) 71777168Skris return (rc); 71877168Skris 71977168Skris n = h.ending_track - h.starting_track + 1; 72077168Skris rc = status (&trk, &junk, &junk, &junk); 72177168Skris if (rc < 0) 72277168Skris return (-1); 72377168Skris 72477168Skris if (arg && *arg) { 72577168Skris if (sscanf (arg, "%u", &off) != 1) { 72677168Skris warnx("invalid command argument"); 72777168Skris return (0); 72877168Skris } else 72977168Skris trk += off * dir; 73077168Skris } else 73177168Skris trk += dir; 73277168Skris 73377168Skris if (trk > h.ending_track) 73477168Skris trk = 1; 73577168Skris 73677168Skris return (play_track (trk, 1, n, 1)); 73777168Skris} 73877168Skris 73910099Sjkhchar *strstatus (int sts) 74010099Sjkh{ 74110099Sjkh switch (sts) { 74210099Sjkh case ASTS_INVALID: return ("invalid"); 74310099Sjkh case ASTS_PLAYING: return ("playing"); 74410099Sjkh case ASTS_PAUSED: return ("paused"); 74510099Sjkh case ASTS_COMPLETED: return ("completed"); 74610099Sjkh case ASTS_ERROR: return ("error"); 74710099Sjkh case ASTS_VOID: return ("void"); 74810099Sjkh default: return ("??"); 74910099Sjkh } 75010099Sjkh} 75110099Sjkh 75213884Sacheint pstatus (char *arg) 75310099Sjkh{ 75410099Sjkh struct ioc_vol v; 75513888Sache struct ioc_read_subchannel ss; 75613888Sache struct cd_sub_channel_info data; 75713884Sache int rc, trk, m, s, f; 75832782Sjmz int what = 0; 75977168Skris char *p, vmcn[(4 * 15) + 1]; 76010099Sjkh 76132782Sjmz while ((p = strtok(arg, " \t"))) { 76232782Sjmz arg = 0; 76332782Sjmz if (!strncasecmp(p, "audio", strlen(p))) 76432782Sjmz what |= STATUS_AUDIO; 76532782Sjmz else if (!strncasecmp(p, "media", strlen(p))) 76632782Sjmz what |= STATUS_MEDIA; 76732782Sjmz else if (!strncasecmp(p, "volume", strlen(p))) 76832782Sjmz what |= STATUS_VOLUME; 76932782Sjmz else { 77032782Sjmz warnx("invalid command arguments"); 77132782Sjmz return 0; 77232782Sjmz } 77332782Sjmz } 77432782Sjmz if (!what) 77532782Sjmz what = STATUS_AUDIO|STATUS_MEDIA|STATUS_VOLUME; 77632782Sjmz if (what & STATUS_AUDIO) { 77732782Sjmz rc = status (&trk, &m, &s, &f); 77832782Sjmz if (rc >= 0) 77910099Sjkh if (verbose) 78032782Sjmz printf ("Audio status = %d<%s>, current track = %d, current position = %d:%02d.%02d\n", 78132782Sjmz rc, strstatus (rc), trk, m, s, f); 78210099Sjkh else 78332782Sjmz printf ("%d %d %d:%02d.%02d\n", rc, trk, m, s, f); 78432782Sjmz else 78513888Sache printf ("No current status info available\n"); 78632782Sjmz } 78732782Sjmz if (what & STATUS_MEDIA) { 78832782Sjmz bzero (&ss, sizeof (ss)); 78932782Sjmz ss.data = &data; 79032782Sjmz ss.data_len = sizeof (data); 79132782Sjmz ss.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 79232782Sjmz ss.data_format = CD_MEDIA_CATALOG; 79332782Sjmz rc = ioctl (fd, CDIOCREADSUBCHANNEL, (char *) &ss); 79432782Sjmz if (rc >= 0) { 79513889Sache printf("Media catalog is %sactive", 79632782Sjmz ss.data->what.media_catalog.mc_valid ? "": "in"); 79716736Sache if (ss.data->what.media_catalog.mc_valid && 79816736Sache ss.data->what.media_catalog.mc_number[0]) 79977168Skris { 80077168Skris strvisx (vmcn, ss.data->what.media_catalog.mc_number, 80177168Skris (sizeof (vmcn) - 1) / 4, VIS_OCTAL | VIS_NL); 80277168Skris printf(", number \"%.*s\"", (int)sizeof (vmcn), vmcn); 80377168Skris } 80413889Sache putchar('\n'); 80532782Sjmz } else 80613888Sache printf("No media catalog info available\n"); 80732782Sjmz } 80832782Sjmz if (what & STATUS_VOLUME) { 80932782Sjmz rc = ioctl (fd, CDIOCGETVOL, &v); 81032782Sjmz if (rc >= 0) 81110099Sjkh if (verbose) 81232782Sjmz printf ("Left volume = %d, right volume = %d\n", 81332782Sjmz v.vol[0], v.vol[1]); 81410099Sjkh else 81532782Sjmz printf ("%d %d\n", v.vol[0], v.vol[1]); 81632782Sjmz else 81713888Sache printf ("No volume level info available\n"); 81832782Sjmz } 81913884Sache return(0); 82013884Sache} 82110099Sjkh 82263091Sjoe/* 82363091Sjoe * dbprog_sum 82463091Sjoe * Convert an integer to its text string representation, and 82563091Sjoe * compute its checksum. Used by dbprog_discid to derive the 82663091Sjoe * disc ID. 82763091Sjoe * 82863091Sjoe * Args: 82963091Sjoe * n - The integer value. 83063091Sjoe * 83163091Sjoe * Return: 83263091Sjoe * The integer checksum. 83363091Sjoe */ 83463091Sjoestatic int 83563091Sjoedbprog_sum(int n) 83663091Sjoe{ 83763091Sjoe char buf[12], 83863091Sjoe *p; 83963091Sjoe int ret = 0; 84063091Sjoe 84163091Sjoe /* For backward compatibility this algorithm must not change */ 84263091Sjoe sprintf(buf, "%u", n); 84363091Sjoe for (p = buf; *p != '\0'; p++) 84463091Sjoe ret += (*p - '0'); 84563091Sjoe 84663091Sjoe return(ret); 84763091Sjoe} 84863091Sjoe 84963091Sjoe 85063091Sjoe/* 85163091Sjoe * dbprog_discid 85263091Sjoe * Compute a magic disc ID based on the number of tracks, 85363091Sjoe * the length of each track, and a checksum of the string 85463091Sjoe * that represents the offset of each track. 85563091Sjoe * 85663091Sjoe * Args: 85763091Sjoe * s - Pointer to the curstat_t structure. 85863091Sjoe * 85963091Sjoe * Return: 86063091Sjoe * The integer disc ID. 86163091Sjoe */ 86263091Sjoestatic u_int 86363091Sjoedbprog_discid() 86463091Sjoe{ 86563091Sjoe struct ioc_toc_header h; 86663091Sjoe int rc; 86763091Sjoe int i, ntr, 86863091Sjoe t = 0, 86963091Sjoe n = 0; 87063091Sjoe 87163091Sjoe rc = ioctl (fd, CDIOREADTOCHEADER, &h); 87263091Sjoe if (rc < 0) 87363091Sjoe return 0; 87463091Sjoe ntr = h.ending_track - h.starting_track + 1; 87563091Sjoe i = msf; 87663091Sjoe msf = 1; 87763091Sjoe rc = read_toc_entrys ((ntr + 1) * sizeof (struct cd_toc_entry)); 87863091Sjoe msf = i; 87963091Sjoe if (rc < 0) 88063091Sjoe return 0; 88163091Sjoe /* For backward compatibility this algorithm must not change */ 88263091Sjoe for (i = 0; i < ntr; i++) { 88363091Sjoe#define TC_MM(a) toc_buffer[a].addr.msf.minute 88463091Sjoe#define TC_SS(a) toc_buffer[a].addr.msf.second 88563091Sjoe n += dbprog_sum((TC_MM(i) * 60) + TC_SS(i)); 88663091Sjoe 88763091Sjoe t += ((TC_MM(i+1) * 60) + TC_SS(i+1)) - 88863091Sjoe ((TC_MM(i) * 60) + TC_SS(i)); 88963091Sjoe } 89063091Sjoe 89163091Sjoe return((n % 0xff) << 24 | t << 8 | ntr); 89263091Sjoe} 89363091Sjoe 89463091Sjoeint cdid () 89563091Sjoe{ 89663091Sjoe u_int id; 89763091Sjoe 89863091Sjoe id = dbprog_discid(); 89963091Sjoe if (id) 90063091Sjoe { 90163091Sjoe if (verbose) 90263091Sjoe printf ("CDID="); 90363091Sjoe printf ("%08x\n",id); 90463091Sjoe } 90563091Sjoe return id ? 0 : 1; 90663091Sjoe} 90763091Sjoe 90813884Sacheint info (char *arg) 90913884Sache{ 91013884Sache struct ioc_toc_header h; 91113884Sache int rc, i, n; 91213884Sache 91310099Sjkh rc = ioctl (fd, CDIOREADTOCHEADER, &h); 91413888Sache if (rc >= 0) { 91510099Sjkh if (verbose) 91610099Sjkh printf ("Starting track = %d, ending track = %d, TOC size = %d bytes\n", 91710099Sjkh h.starting_track, h.ending_track, h.len); 91810099Sjkh else 91910099Sjkh printf ("%d %d %d\n", h.starting_track, 92010099Sjkh h.ending_track, h.len); 92113888Sache } else { 92229103Scharnier warn("getting toc header"); 92310099Sjkh return (rc); 92410099Sjkh } 92510099Sjkh 92610099Sjkh n = h.ending_track - h.starting_track + 1; 92710099Sjkh rc = read_toc_entrys ((n + 1) * sizeof (struct cd_toc_entry)); 92810099Sjkh if (rc < 0) 92910099Sjkh return (rc); 93013985Sache 93110099Sjkh if (verbose) { 93210099Sjkh printf ("track start duration block length type\n"); 93310099Sjkh printf ("-------------------------------------------------\n"); 93410099Sjkh } 93513985Sache 93610099Sjkh for (i = 0; i < n; i++) { 93710099Sjkh printf ("%5d ", toc_buffer[i].track); 93810099Sjkh prtrack (toc_buffer + i, 0); 93910099Sjkh } 94013867Sache printf ("%5d ", toc_buffer[n].track); 94110099Sjkh prtrack (toc_buffer + n, 1); 94210099Sjkh return (0); 94310099Sjkh} 94410099Sjkh 94513985Sachevoid lba2msf (unsigned long lba, u_char *m, u_char *s, u_char *f) 94610099Sjkh{ 94713985Sache lba += 150; /* block start offset */ 94813985Sache lba &= 0xffffff; /* negative lbas use only 24 bits */ 94910099Sjkh *m = lba / (60 * 75); 95010099Sjkh lba %= (60 * 75); 95110099Sjkh *s = lba / 75; 95210099Sjkh *f = lba % 75; 95310099Sjkh} 95410099Sjkh 95513985Sacheunsigned int msf2lba (u_char m, u_char s, u_char f) 95610099Sjkh{ 95710099Sjkh return (((m * 60) + s) * 75 + f) - 150; 95810099Sjkh} 95910099Sjkh 96010099Sjkhvoid prtrack (struct cd_toc_entry *e, int lastflag) 96110099Sjkh{ 96210099Sjkh int block, next, len; 96310099Sjkh u_char m, s, f; 96410099Sjkh 96513884Sache if (msf) { 96613884Sache /* Print track start */ 96713884Sache printf ("%2d:%02d.%02d ", e->addr.msf.minute, 96813884Sache e->addr.msf.second, e->addr.msf.frame); 96910099Sjkh 97013884Sache block = msf2lba (e->addr.msf.minute, e->addr.msf.second, 97113884Sache e->addr.msf.frame); 97213884Sache } else { 97313884Sache block = ntohl(e->addr.lba); 97413884Sache lba2msf(block, &m, &s, &f); 97513884Sache /* Print track start */ 97613884Sache printf ("%2d:%02d.%02d ", m, s, f); 97713884Sache } 97810099Sjkh if (lastflag) { 97910099Sjkh /* Last track -- print block */ 98010099Sjkh printf (" - %6d - -\n", block); 98110099Sjkh return; 98210099Sjkh } 98310099Sjkh 98413884Sache if (msf) 98513884Sache next = msf2lba (e[1].addr.msf.minute, e[1].addr.msf.second, 98613884Sache e[1].addr.msf.frame); 98713884Sache else 98813884Sache next = ntohl(e[1].addr.lba); 98910099Sjkh len = next - block; 99010099Sjkh lba2msf (len, &m, &s, &f); 99110099Sjkh 99210099Sjkh /* Print duration, block, length, type */ 99310099Sjkh printf ("%2d:%02d.%02d %6d %6d %5s\n", m, s, f, block, len, 99413985Sache (e->control & 4) ? "data" : "audio"); 99510099Sjkh} 99610099Sjkh 99710099Sjkhint play_track (int tstart, int istart, int tend, int iend) 99810099Sjkh{ 99910099Sjkh struct ioc_play_track t; 100010099Sjkh 100110099Sjkh t.start_track = tstart; 100210099Sjkh t.start_index = istart; 100310099Sjkh t.end_track = tend; 100410099Sjkh t.end_index = iend; 100513985Sache 100610099Sjkh return ioctl (fd, CDIOCPLAYTRACKS, &t); 100710099Sjkh} 100810099Sjkh 100910099Sjkhint play_blocks (int blk, int len) 101010099Sjkh{ 101113985Sache struct ioc_play_blocks t; 101210099Sjkh 101310099Sjkh t.blk = blk; 101410099Sjkh t.len = len; 101513985Sache 101610099Sjkh return ioctl (fd, CDIOCPLAYBLOCKS, &t); 101710099Sjkh} 101810099Sjkh 101913985Sacheint setvol (int left, int right) 102010099Sjkh{ 102113985Sache struct ioc_vol v; 102210099Sjkh 102313985Sache v.vol[0] = left; 102413985Sache v.vol[1] = right; 102510099Sjkh v.vol[2] = 0; 102610099Sjkh v.vol[3] = 0; 102713985Sache 102810099Sjkh return ioctl (fd, CDIOCSETVOL, &v); 102910099Sjkh} 103010099Sjkh 103110099Sjkhint read_toc_entrys (int len) 103210099Sjkh{ 103310099Sjkh struct ioc_read_toc_entry t; 103410099Sjkh 103513884Sache t.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 103613737Sache t.starting_track = 0; 103710099Sjkh t.data_len = len; 103810099Sjkh t.data = toc_buffer; 103913985Sache 104013985Sache return (ioctl (fd, CDIOREADTOCENTRYS, (char *) &t)); 104110099Sjkh} 104210099Sjkh 104310099Sjkhint play_msf (int start_m, int start_s, int start_f, 104413985Sache int end_m, int end_s, int end_f) 104510099Sjkh{ 104613985Sache struct ioc_play_msf a; 104710099Sjkh 104810099Sjkh a.start_m = start_m; 104910099Sjkh a.start_s = start_s; 105010099Sjkh a.start_f = start_f; 105110099Sjkh a.end_m = end_m; 105210099Sjkh a.end_s = end_s; 105310099Sjkh a.end_f = end_f; 105413985Sache 105510099Sjkh return ioctl (fd, CDIOCPLAYMSF, (char *) &a); 105610099Sjkh} 105710099Sjkh 105810099Sjkhint status (int *trk, int *min, int *sec, int *frame) 105910099Sjkh{ 106010099Sjkh struct ioc_read_subchannel s; 106110099Sjkh struct cd_sub_channel_info data; 106213884Sache u_char mm, ss, ff; 106310099Sjkh 106410099Sjkh bzero (&s, sizeof (s)); 106510099Sjkh s.data = &data; 106610099Sjkh s.data_len = sizeof (data); 106713884Sache s.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 106810099Sjkh s.data_format = CD_CURRENT_POSITION; 106913985Sache 107010099Sjkh if (ioctl (fd, CDIOCREADSUBCHANNEL, (char *) &s) < 0) 107110099Sjkh return -1; 107213985Sache 107310099Sjkh *trk = s.data->what.position.track_number; 107413884Sache if (msf) { 107513884Sache *min = s.data->what.position.reladdr.msf.minute; 107613884Sache *sec = s.data->what.position.reladdr.msf.second; 107713884Sache *frame = s.data->what.position.reladdr.msf.frame; 107813884Sache } else { 107913884Sache lba2msf(ntohl(s.data->what.position.reladdr.lba), 108013884Sache &mm, &ss, &ff); 108113884Sache *min = mm; 108213884Sache *sec = ss; 108313884Sache *frame = ff; 108413884Sache } 108513985Sache 108610099Sjkh return s.data->header.audio_status; 108710099Sjkh} 108810099Sjkh 108950039Smdoddconst char * 109050039Smdoddcdcontrol_prompt() 109110099Sjkh{ 109250039Smdodd return ("cdcontrol> "); 109350039Smdodd} 109450039Smdodd 109550039Smdoddchar * 109650039Smdoddinput (int *cmd) 109750039Smdodd{ 109850039Smdodd#define MAXLINE 80 109950039Smdodd static EditLine *el = NULL; 110050039Smdodd static History *hist = NULL; 110150039Smdodd static char buf[MAXLINE]; 110250039Smdodd int num = 0; 110350071Smdodd int len; 110450039Smdodd const char *bp = NULL; 110510099Sjkh char *p; 110610099Sjkh 110710099Sjkh do { 110850039Smdodd if (verbose) { 110950039Smdodd if (!el) { 111050039Smdodd el = el_init("cdcontrol", stdin, stdout); 111150039Smdodd hist = history_init(); 111250039Smdodd history(hist, H_EVENT, 100); 111350039Smdodd el_set(el, EL_HIST, history, hist); 111450039Smdodd el_set(el, EL_EDITOR, "emacs"); 111550039Smdodd el_set(el, EL_PROMPT, cdcontrol_prompt); 111650039Smdodd el_set(el, EL_SIGNAL, 1); 111750042Smdodd el_source(el, NULL); 111850039Smdodd } 111963070Smckay if ((bp = el_gets(el, &num)) == NULL || num == 0) { 112063070Smckay *cmd = CMD_QUIT; 112163070Smckay fprintf (stderr, "\r\n"); 112250039Smdodd return (0); 112363070Smckay } 112450039Smdodd 112550071Smdodd len = (num > MAXLINE) ? MAXLINE : num; 112650071Smdodd memcpy(buf, bp, len); 112750071Smdodd buf[len] = 0; 112850039Smdodd history(hist, H_ENTER, bp); 112950039Smdodd#undef MAXLINE 113050039Smdodd 113150039Smdodd } else { 113250039Smdodd if (! fgets (buf, sizeof (buf), stdin)) { 113350039Smdodd *cmd = CMD_QUIT; 113450039Smdodd fprintf (stderr, "\r\n"); 113550039Smdodd return (0); 113650039Smdodd } 113710099Sjkh } 113810099Sjkh p = parse (buf, cmd); 113910099Sjkh } while (! p); 114010099Sjkh return (p); 114110099Sjkh} 114210099Sjkh 114310099Sjkhchar *parse (char *buf, int *cmd) 114410099Sjkh{ 114510099Sjkh struct cmdtab *c; 114610099Sjkh char *p; 114710099Sjkh int len; 114810099Sjkh 114913985Sache for (p=buf; isspace (*p); p++) 115013985Sache continue; 115110099Sjkh 115213985Sache if (isdigit (*p) || (p[0] == '#' && isdigit (p[1]))) { 115313985Sache *cmd = CMD_PLAY; 115413985Sache return (p); 115577168Skris } else if (*p == '+') { 115677168Skris *cmd = CMD_NEXT; 115777168Skris return (p + 1); 115877168Skris } else if (*p == '-') { 115977168Skris *cmd = CMD_PREVIOUS; 116077168Skris return (p + 1); 116113985Sache } 116210099Sjkh 116313985Sache for (buf = p; *p && ! isspace (*p); p++) 116413985Sache continue; 116513985Sache 116613985Sache len = p - buf; 116710099Sjkh if (! len) 116810099Sjkh return (0); 116913985Sache 117013985Sache if (*p) { /* It must be a spacing character! */ 117113985Sache char *q; 117213985Sache 117313985Sache *p++ = 0; 117413985Sache for (q=p; *q && *q != '\n' && *q != '\r'; q++) 117513985Sache continue; 117613985Sache *q = 0; 117713985Sache } 117813985Sache 117910099Sjkh *cmd = -1; 118010099Sjkh for (c=cmdtab; c->name; ++c) { 118113985Sache /* Is it an exact match? */ 118213985Sache if (! strcasecmp (buf, c->name)) { 118313985Sache *cmd = c->command; 118413985Sache break; 118513985Sache } 118613985Sache 118713985Sache /* Try short hand forms then... */ 118813985Sache if (len >= c->min && ! strncasecmp (buf, c->name, len)) { 118913985Sache if (*cmd != -1 && *cmd != c->command) { 119029103Scharnier warnx("ambiguous command"); 119113985Sache return (0); 119213985Sache } 119310099Sjkh *cmd = c->command; 119413985Sache } 119513985Sache } 119610099Sjkh 119710099Sjkh if (*cmd == -1) { 119829103Scharnier warnx("invalid command, enter ``help'' for commands"); 119910099Sjkh return (0); 120010099Sjkh } 120113985Sache 120213985Sache while (isspace (*p)) 120313985Sache p++; 120410099Sjkh return p; 120510099Sjkh} 120610099Sjkh 120710099Sjkhint open_cd () 120810099Sjkh{ 120954164Sjoe char devbuf[MAXPATHLEN]; 121010099Sjkh 121110099Sjkh if (fd > -1) 121210099Sjkh return (1); 121313985Sache 121454164Sjoe if (*cdname == '/') { 121554164Sjoe snprintf (devbuf, MAXPATHLEN, "%s", cdname); 121661105Smsmith } else { 121769793Sobrien snprintf (devbuf, MAXPATHLEN, "%s%s", _PATH_DEV, cdname); 121854164Sjoe } 121913985Sache 122010099Sjkh fd = open (devbuf, O_RDONLY); 122113985Sache 122210099Sjkh if (fd < 0 && errno == ENOENT) { 122313985Sache strcat (devbuf, DEFAULT_CD_PARTITION); 122410099Sjkh fd = open (devbuf, O_RDONLY); 122510099Sjkh } 122613985Sache 122710099Sjkh if (fd < 0) { 122813985Sache if (errno == ENXIO) { 122913985Sache /* ENXIO has an overloaded meaning here. 123013985Sache * The original "Device not configured" should 123113985Sache * be interpreted as "No disc in drive %s". */ 123229103Scharnier warnx("no disc in drive %s", devbuf); 123313985Sache return (0); 123410099Sjkh } 123529103Scharnier err(1, "%s", devbuf); 123610099Sjkh } 123710099Sjkh return (1); 123810099Sjkh} 1239