cdcontrol.c revision 69793
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 69793 2000-12-09 09:35:55Z obrien $"; 2429103Scharnier#endif /* not lint */ 2529103Scharnier 2613985Sache#include <ctype.h> 2729103Scharnier#include <err.h> 2829103Scharnier#include <errno.h> 2969793Sobrien#include <paths.h> 3010099Sjkh#include <stdio.h> 3110099Sjkh#include <stdlib.h> 3210099Sjkh#include <string.h> 3310099Sjkh#include <unistd.h> 3410099Sjkh#include <sys/file.h> 3510099Sjkh#include <sys/cdio.h> 3610099Sjkh#include <sys/ioctl.h> 3754164Sjoe#include <sys/param.h> 3850039Smdodd#include <histedit.h> 3910099Sjkh 4013884Sache#define VERSION "2.0" 4110099Sjkh 4213985Sache#define ASTS_INVALID 0x00 /* Audio status byte not valid */ 4313985Sache#define ASTS_PLAYING 0x11 /* Audio play operation in progress */ 4413985Sache#define ASTS_PAUSED 0x12 /* Audio play operation paused */ 4513985Sache#define ASTS_COMPLETED 0x13 /* Audio play operation successfully completed */ 4613985Sache#define ASTS_ERROR 0x14 /* Audio play operation stopped due to error */ 4713985Sache#define ASTS_VOID 0x15 /* No current audio status to return */ 4810099Sjkh 4913985Sache#ifndef DEFAULT_CD_DRIVE 5013985Sache# define DEFAULT_CD_DRIVE "/dev/cd0c" 5113985Sache#endif 5213985Sache 5313985Sache#ifndef DEFAULT_CD_PARTITION 5413985Sache# define DEFAULT_CD_PARTITION "c" 5513985Sache#endif 5613985Sache 5713985Sache#define CMD_DEBUG 1 5813985Sache#define CMD_EJECT 2 5913985Sache#define CMD_HELP 3 6013985Sache#define CMD_INFO 4 6113985Sache#define CMD_PAUSE 5 6213985Sache#define CMD_PLAY 6 6313985Sache#define CMD_QUIT 7 6413985Sache#define CMD_RESUME 8 6513985Sache#define CMD_STOP 9 6613985Sache#define CMD_VOLUME 10 6713985Sache#define CMD_CLOSE 11 6813985Sache#define CMD_RESET 12 6913985Sache#define CMD_SET 13 7013985Sache#define CMD_STATUS 14 7163091Sjoe#define CMD_CDID 15 7232782Sjmz#define STATUS_AUDIO 0x1 7332782Sjmz#define STATUS_MEDIA 0x2 7432782Sjmz#define STATUS_VOLUME 0x4 7513985Sache 7610099Sjkhstruct cmdtab { 7710099Sjkh int command; 7810099Sjkh char *name; 7913985Sache unsigned min; 8010099Sjkh char *args; 8110099Sjkh} cmdtab[] = { 8213985Sache{ CMD_CLOSE, "close", 1, "" }, 8313985Sache{ CMD_DEBUG, "debug", 1, "on | off" }, 8413985Sache{ CMD_EJECT, "eject", 1, "" }, 8513985Sache{ CMD_HELP, "?", 1, 0 }, 8613985Sache{ CMD_HELP, "help", 1, "" }, 8713985Sache{ CMD_INFO, "info", 1, "" }, 8813985Sache{ CMD_PAUSE, "pause", 2, "" }, 8913985Sache{ CMD_PLAY, "play", 1, "min1:sec1[.fram1] [min2:sec2[.fram2]]" }, 9013985Sache{ CMD_PLAY, "play", 1, "track1[.index1] [track2[.index2]]" }, 9113985Sache{ CMD_PLAY, "play", 1, "tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]]" }, 9213985Sache{ CMD_PLAY, "play", 1, "[#block [len]]" }, 9313985Sache{ CMD_QUIT, "quit", 1, "" }, 9413985Sache{ CMD_RESET, "reset", 4, "" }, 9513985Sache{ CMD_RESUME, "resume", 1, "" }, 9613985Sache{ CMD_SET, "set", 2, "msf | lba" }, 9732782Sjmz{ CMD_STATUS, "status", 1, "[audio | media | volume]" }, 9813985Sache{ CMD_STOP, "stop", 3, "" }, 9913985Sache{ CMD_VOLUME, "volume", 1, "<l> <r> | left | right | mute | mono | stereo" }, 10063091Sjoe{ CMD_CDID, "cdid", 2, "" }, 10113985Sache{ 0, } 10210099Sjkh}; 10310099Sjkh 10413985Sachestruct cd_toc_entry toc_buffer[100]; 10510099Sjkh 10613985Sacheconst char *cdname; 10713985Sacheint fd = -1; 10813985Sacheint verbose = 1; 10913985Sacheint msf = 1; 11010099Sjkh 11113985Sacheint setvol __P((int, int)); 11213985Sacheint read_toc_entrys __P((int)); 11313985Sacheint play_msf __P((int, int, int, int, int, int)); 11413985Sacheint play_track __P((int, int, int, int)); 11513985Sacheint get_vol __P((int *, int *)); 11613985Sacheint status __P((int *, int *, int *, int *)); 11713985Sacheint open_cd __P((void)); 11813985Sacheint play __P((char *arg)); 11913985Sacheint info __P((char *arg)); 12063091Sjoeint cdid __P((void)); 12113985Sacheint pstatus __P((char *arg)); 12213985Sachechar *input __P((int *)); 12313985Sachevoid prtrack __P((struct cd_toc_entry *e, int lastflag)); 12413985Sachevoid lba2msf __P((unsigned long lba, 12513985Sache u_char *m, u_char *s, u_char *f)); 12613985Sacheunsigned int msf2lba __P((u_char m, u_char s, u_char f)); 12713985Sacheint play_blocks __P((int blk, int len)); 12813985Sacheint run __P((int cmd, char *arg)); 12913985Sachechar *parse __P((char *buf, int *cmd)); 13010099Sjkh 13110099Sjkhvoid help () 13210099Sjkh{ 13310099Sjkh struct cmdtab *c; 13413985Sache char *s, n; 13513985Sache int i; 13610099Sjkh 13710099Sjkh for (c=cmdtab; c->name; ++c) { 13810099Sjkh if (! c->args) 13910099Sjkh continue; 14013985Sache printf("\t"); 14113985Sache for (i = c->min, s = c->name; *s; s++, i--) { 14213985Sache if (i > 0) 14313985Sache n = toupper(*s); 14413985Sache else 14513985Sache n = *s; 14613985Sache putchar(n); 14713985Sache } 14810099Sjkh if (*c->args) 14910099Sjkh printf (" %s", c->args); 15010099Sjkh printf ("\n"); 15110099Sjkh } 15213985Sache printf ("\n\tThe word \"play\" is not required for the play commands.\n"); 15313985Sache printf ("\tThe plain target address is taken as a synonym for play.\n"); 15410099Sjkh} 15510099Sjkh 15610099Sjkhvoid usage () 15710099Sjkh{ 15843479Sbillf fprintf (stderr, "usage: cdcontrol [-sv] [-f device] [command ...]\n"); 15910099Sjkh exit (1); 16010099Sjkh} 16110099Sjkh 16210099Sjkhint main (int argc, char **argv) 16310099Sjkh{ 16410099Sjkh int cmd; 16510099Sjkh char *arg; 16610099Sjkh 16713985Sache cdname = getenv ("MUSIC_CD"); 16810099Sjkh if (! cdname) 16913985Sache cdname = getenv ("CD_DRIVE"); 17013985Sache if (! cdname) 17113985Sache cdname = getenv ("DISC"); 17213985Sache if (! cdname) 17310099Sjkh cdname = getenv ("CDPLAY"); 17410099Sjkh 17510099Sjkh for (;;) { 17610099Sjkh switch (getopt (argc, argv, "svhf:")) { 17710099Sjkh case EOF: 17810099Sjkh break; 17910099Sjkh case 's': 18010099Sjkh verbose = 0; 18110099Sjkh continue; 18210099Sjkh case 'v': 18310099Sjkh verbose = 2; 18410099Sjkh continue; 18510099Sjkh case 'f': 18610099Sjkh cdname = optarg; 18710099Sjkh continue; 18810099Sjkh case 'h': 18910099Sjkh default: 19010099Sjkh usage (); 19110099Sjkh } 19210099Sjkh break; 19310099Sjkh } 19410099Sjkh argc -= optind; 19510099Sjkh argv += optind; 19610099Sjkh 19713985Sache if (argc > 0 && ! strcasecmp (*argv, "help")) 19810099Sjkh usage (); 19910099Sjkh 20010099Sjkh if (! cdname) { 20113985Sache cdname = DEFAULT_CD_DRIVE; 20229103Scharnier warnx("no CD device name specified, defaulting to %s", cdname); 20310099Sjkh } 20410099Sjkh 20510099Sjkh if (argc > 0) { 20610099Sjkh char buf[80], *p; 20710099Sjkh int len; 20810099Sjkh 20913985Sache for (p=buf; argc-->0; ++argv) { 21010099Sjkh len = strlen (*argv); 21113985Sache 21210099Sjkh if (p + len >= buf + sizeof (buf) - 1) 21310099Sjkh usage (); 21413985Sache 21510099Sjkh if (p > buf) 21610099Sjkh *p++ = ' '; 21713985Sache 21810099Sjkh strcpy (p, *argv); 21910099Sjkh p += len; 22010099Sjkh } 22110099Sjkh *p = 0; 22210099Sjkh arg = parse (buf, &cmd); 22313985Sache return (run (cmd, arg)); 22410099Sjkh } 22510099Sjkh 22610099Sjkh if (verbose == 1) 22710099Sjkh verbose = isatty (0); 22813985Sache 22910099Sjkh if (verbose) { 23013985Sache printf ("Compact Disc Control utility, version %s\n", VERSION); 23110099Sjkh printf ("Type `?' for command list\n\n"); 23210099Sjkh } 23310099Sjkh 23410099Sjkh for (;;) { 23510099Sjkh arg = input (&cmd); 23610099Sjkh if (run (cmd, arg) < 0) { 23710099Sjkh if (verbose) 23829103Scharnier warn(NULL); 23910099Sjkh close (fd); 24010099Sjkh fd = -1; 24110099Sjkh } 24210099Sjkh fflush (stdout); 24310099Sjkh } 24410099Sjkh} 24510099Sjkh 24610099Sjkhint run (int cmd, char *arg) 24710099Sjkh{ 24810099Sjkh int l, r, rc; 24910099Sjkh 25010099Sjkh switch (cmd) { 25113985Sache 25210099Sjkh case CMD_QUIT: 25310099Sjkh exit (0); 25410099Sjkh 25513985Sache case CMD_INFO: 25613985Sache if (fd < 0 && ! open_cd ()) 25713985Sache return (0); 25810099Sjkh 25910099Sjkh return info (arg); 26010099Sjkh 26163091Sjoe case CMD_CDID: 26263091Sjoe if (fd < 0 && ! open_cd ()) 26363091Sjoe return (0); 26463091Sjoe 26563091Sjoe return cdid (); 26663091Sjoe 26713884Sache case CMD_STATUS: 26813985Sache if (fd < 0 && ! open_cd ()) 26913985Sache return (0); 27013985Sache 27113884Sache return pstatus (arg); 27213884Sache 27310099Sjkh case CMD_PAUSE: 27413985Sache if (fd < 0 && ! open_cd ()) 27513985Sache return (0); 27613985Sache 27710099Sjkh return ioctl (fd, CDIOCPAUSE); 27810099Sjkh 27910099Sjkh case CMD_RESUME: 28013985Sache if (fd < 0 && ! open_cd ()) 28113985Sache return (0); 28213985Sache 28310099Sjkh return ioctl (fd, CDIOCRESUME); 28410099Sjkh 28510099Sjkh case CMD_STOP: 28613985Sache if (fd < 0 && ! open_cd ()) 28713985Sache return (0); 28810099Sjkh 28913985Sache rc = ioctl (fd, CDIOCSTOP); 29013985Sache 29113985Sache (void) ioctl (fd, CDIOCALLOW); 29213985Sache 29313985Sache return (rc); 29413985Sache 29513884Sache case CMD_RESET: 29613985Sache if (fd < 0 && ! open_cd ()) 29713985Sache return (0); 29813985Sache 29913884Sache rc = ioctl (fd, CDIOCRESET); 30013884Sache if (rc < 0) 30113884Sache return rc; 30213884Sache close(fd); 30313884Sache fd = -1; 30413884Sache return (0); 30513884Sache 30610099Sjkh case CMD_DEBUG: 30713985Sache if (fd < 0 && ! open_cd ()) 30813985Sache return (0); 30913985Sache 31013985Sache if (! strcasecmp (arg, "on")) 31110099Sjkh return ioctl (fd, CDIOCSETDEBUG); 31213985Sache 31313985Sache if (! strcasecmp (arg, "off")) 31410099Sjkh return ioctl (fd, CDIOCCLRDEBUG); 31513985Sache 31629103Scharnier warnx("invalid command arguments"); 31713985Sache 31810099Sjkh return (0); 31910099Sjkh 32010099Sjkh case CMD_EJECT: 32113985Sache if (fd < 0 && ! open_cd ()) 32213985Sache return (0); 32313985Sache 32410099Sjkh (void) ioctl (fd, CDIOCALLOW); 32510099Sjkh rc = ioctl (fd, CDIOCEJECT); 32610099Sjkh if (rc < 0) 32710099Sjkh return (rc); 32813865Sache return (0); 32913865Sache 33013985Sache case CMD_CLOSE: 33113985Sache if (fd < 0 && ! open_cd ()) 33213985Sache return (0); 33313985Sache 33413985Sache (void) ioctl (fd, CDIOCALLOW); 33513865Sache rc = ioctl (fd, CDIOCCLOSE); 33613865Sache if (rc < 0) 33713865Sache return (rc); 33813865Sache close(fd); 33910099Sjkh fd = -1; 34010099Sjkh return (0); 34110099Sjkh 34210099Sjkh case CMD_PLAY: 34313985Sache if (fd < 0 && ! open_cd ()) 34413985Sache return (0); 34513985Sache 34613985Sache while (isspace (*arg)) 34713985Sache arg++; 34813985Sache 34910099Sjkh return play (arg); 35010099Sjkh 35113884Sache case CMD_SET: 35213985Sache if (! strcasecmp (arg, "msf")) 35313884Sache msf = 1; 35413985Sache else if (! strcasecmp (arg, "lba")) 35513884Sache msf = 0; 35613884Sache else 35729103Scharnier warnx("invalid command arguments"); 35813884Sache return (0); 35913884Sache 36010099Sjkh case CMD_VOLUME: 36113985Sache if (fd < 0 && !open_cd ()) 36213985Sache return (0); 36310099Sjkh 36413985Sache if (! strncasecmp (arg, "left", strlen(arg))) 36510099Sjkh return ioctl (fd, CDIOCSETLEFT); 36613985Sache 36713985Sache if (! strncasecmp (arg, "right", strlen(arg))) 36810099Sjkh return ioctl (fd, CDIOCSETRIGHT); 36913985Sache 37013985Sache if (! strncasecmp (arg, "mono", strlen(arg))) 37110099Sjkh return ioctl (fd, CDIOCSETMONO); 37213985Sache 37313985Sache if (! strncasecmp (arg, "stereo", strlen(arg))) 37410099Sjkh return ioctl (fd, CDIOCSETSTERIO); 37510099Sjkh 37613985Sache if (! strncasecmp (arg, "mute", strlen(arg))) 37713985Sache return ioctl (fd, CDIOCSETMUTE); 37813985Sache 37910099Sjkh if (2 != sscanf (arg, "%d %d", &l, &r)) { 38029103Scharnier warnx("invalid command arguments"); 38110099Sjkh return (0); 38210099Sjkh } 38313985Sache 38410099Sjkh return setvol (l, r); 38513985Sache 38613985Sache default: 38713985Sache case CMD_HELP: 38813985Sache help (); 38913985Sache return (0); 39013985Sache 39110099Sjkh } 39210099Sjkh} 39310099Sjkh 39410099Sjkhint play (char *arg) 39510099Sjkh{ 39610099Sjkh struct ioc_toc_header h; 39710099Sjkh int rc, n, start, end = 0, istart = 1, iend = 1; 39810099Sjkh 39910099Sjkh rc = ioctl (fd, CDIOREADTOCHEADER, &h); 40013985Sache 40110099Sjkh if (rc < 0) 40210099Sjkh return (rc); 40310099Sjkh 40410099Sjkh n = h.ending_track - h.starting_track + 1; 40510099Sjkh rc = read_toc_entrys ((n + 1) * sizeof (struct cd_toc_entry)); 40613985Sache 40710099Sjkh if (rc < 0) 40810099Sjkh return (rc); 40910099Sjkh 41013989Sache if (! arg || ! *arg) { 41113985Sache /* Play the whole disc */ 41213989Sache if (msf) 41313989Sache return play_blocks (0, msf2lba (toc_buffer[n].addr.msf.minute, 41413989Sache toc_buffer[n].addr.msf.second, 41513989Sache toc_buffer[n].addr.msf.frame)); 41613989Sache else 41713989Sache return play_blocks (0, ntohl(toc_buffer[n].addr.lba)); 41813989Sache } 41910099Sjkh 42010099Sjkh if (strchr (arg, '#')) { 42113985Sache /* Play block #blk [ len ] */ 42210099Sjkh int blk, len = 0; 42310099Sjkh 42410099Sjkh if (2 != sscanf (arg, "#%d%d", &blk, &len) && 42513985Sache 1 != sscanf (arg, "#%d", &blk)) 42613985Sache goto Clean_up; 42713985Sache 42813989Sache if (len == 0) { 42913989Sache if (msf) 43013989Sache len = msf2lba (toc_buffer[n].addr.msf.minute, 43113989Sache toc_buffer[n].addr.msf.second, 43213989Sache toc_buffer[n].addr.msf.frame) - blk; 43313989Sache else 43413989Sache len = ntohl(toc_buffer[n].addr.lba) - blk; 43513989Sache } 43610099Sjkh return play_blocks (blk, len); 43710099Sjkh } 43810099Sjkh 43910099Sjkh if (strchr (arg, ':')) { 44010099Sjkh /* 44110099Sjkh * Play MSF m1:s1 [ .f1 ] [ m2:s2 [ .f2 ] ] 44213985Sache * 44313985Sache * Will now also undestand timed addresses relative 44413985Sache * to the beginning of a track in the form... 44513985Sache * 44613985Sache * tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]] 44710099Sjkh */ 44813985Sache unsigned tr1, tr2; 44913985Sache unsigned m1, m2, s1, s2, f1, f2; 45013989Sache unsigned char tm, ts, tf; 45110099Sjkh 45213985Sache tr2 = m2 = s2 = f2 = f1 = 0; 45313985Sache if (8 == sscanf (arg, "%d %d:%d.%d %d %d:%d.%d", 45413985Sache &tr1, &m1, &s1, &f1, &tr2, &m2, &s2, &f2)) 45513985Sache goto Play_Relative_Addresses; 45613985Sache 45713985Sache tr2 = m2 = s2 = f2 = f1 = 0; 45813985Sache if (7 == sscanf (arg, "%d %d:%d %d %d:%d.%d", 45913985Sache &tr1, &m1, &s1, &tr2, &m2, &s2, &f2)) 46013985Sache goto Play_Relative_Addresses; 46113985Sache 46213985Sache tr2 = m2 = s2 = f2 = f1 = 0; 46313985Sache if (7 == sscanf (arg, "%d %d:%d.%d %d %d:%d", 46413985Sache &tr1, &m1, &s1, &f1, &tr2, &m2, &s2)) 46513985Sache goto Play_Relative_Addresses; 46613985Sache 46713985Sache tr2 = m2 = s2 = f2 = f1 = 0; 46813985Sache if (7 == sscanf (arg, "%d %d:%d.%d %d:%d.%d", 46913985Sache &tr1, &m1, &s1, &f1, &m2, &s2, &f2)) 47013985Sache goto Play_Relative_Addresses; 47113985Sache 47213985Sache tr2 = m2 = s2 = f2 = f1 = 0; 47313985Sache if (6 == sscanf (arg, "%d %d:%d.%d %d:%d", 47413985Sache &tr1, &m1, &s1, &f1, &m2, &s2)) 47513985Sache goto Play_Relative_Addresses; 47613985Sache 47713985Sache tr2 = m2 = s2 = f2 = f1 = 0; 47813985Sache if (6 == sscanf (arg, "%d %d:%d %d:%d.%d", 47913985Sache &tr1, &m1, &s1, &m2, &s2, &f2)) 48013985Sache goto Play_Relative_Addresses; 48113985Sache 48213985Sache tr2 = m2 = s2 = f2 = f1 = 0; 48313985Sache if (6 == sscanf (arg, "%d %d:%d.%d %d %d", 48413985Sache &tr1, &m1, &s1, &f1, &tr2, &m2)) 48513985Sache goto Play_Relative_Addresses; 48613985Sache 48713985Sache tr2 = m2 = s2 = f2 = f1 = 0; 48813985Sache if (5 == sscanf (arg, "%d %d:%d %d:%d", &tr1, &m1, &s1, &m2, &s2)) 48913985Sache goto Play_Relative_Addresses; 49013985Sache 49113985Sache tr2 = m2 = s2 = f2 = f1 = 0; 49213985Sache if (5 == sscanf (arg, "%d %d:%d %d %d", 49313985Sache &tr1, &m1, &s1, &tr2, &m2)) 49413985Sache goto Play_Relative_Addresses; 49513985Sache 49613985Sache tr2 = m2 = s2 = f2 = f1 = 0; 49713985Sache if (5 == sscanf (arg, "%d %d:%d.%d %d", 49813985Sache &tr1, &m1, &s1, &f1, &tr2)) 49913985Sache goto Play_Relative_Addresses; 50013985Sache 50113985Sache tr2 = m2 = s2 = f2 = f1 = 0; 50213985Sache if (4 == sscanf (arg, "%d %d:%d %d", &tr1, &m1, &s1, &tr2)) 50313985Sache goto Play_Relative_Addresses; 50413985Sache 50513985Sache tr2 = m2 = s2 = f2 = f1 = 0; 50613985Sache if (4 == sscanf (arg, "%d %d:%d.%d", &tr1, &m1, &s1, &f1)) 50713985Sache goto Play_Relative_Addresses; 50813985Sache 50913985Sache tr2 = m2 = s2 = f2 = f1 = 0; 51013985Sache if (3 == sscanf (arg, "%d %d:%d", &tr1, &m1, &s1)) 51113985Sache goto Play_Relative_Addresses; 51213985Sache 51313985Sache tr2 = m2 = s2 = f2 = f1 = 0; 51413985Sache goto Try_Absolute_Timed_Addresses; 51513985Sache 51613985SachePlay_Relative_Addresses: 51713985Sache if (! tr1) 51813985Sache tr1 = 1; 51913985Sache else if (tr1 > n) 52013985Sache tr1 = n; 52113985Sache 52213989Sache if (msf) { 52313989Sache tm = toc_buffer[tr1].addr.msf.minute; 52413989Sache ts = toc_buffer[tr1].addr.msf.second; 52513989Sache tf = toc_buffer[tr1].addr.msf.frame; 52613989Sache } else 52713989Sache lba2msf(ntohl(toc_buffer[tr1].addr.lba), 52813989Sache &tm, &ts, &tf); 52913989Sache if ((m1 > tm) 53013989Sache || ((m1 == tm) 53113989Sache && ((s1 > ts) 53213989Sache || ((s1 == ts) 53313989Sache && (f1 > tf))))) { 53413985Sache printf ("Track %d is not that long.\n", tr1); 53513985Sache return (0); 53613985Sache } 53713985Sache 53813985Sache tr1--; 53913985Sache 54013989Sache f1 += tf; 54113985Sache if (f1 >= 75) { 54213985Sache s1 += f1 / 75; 54313985Sache f1 %= 75; 54413985Sache } 54513985Sache 54613989Sache s1 += ts; 54713985Sache if (s1 >= 60) { 54813985Sache m1 += s1 / 60; 54913985Sache s1 %= 60; 55013985Sache } 55113985Sache 55213989Sache m1 += tm; 55313985Sache 55413985Sache if (! tr2) { 55513985Sache if (m2 || s2 || f2) { 55613985Sache tr2 = tr1; 55713985Sache f2 += f1; 55813985Sache if (f2 >= 75) { 55913985Sache s2 += f2 / 75; 56013985Sache f2 %= 75; 56113985Sache } 56213985Sache 56313985Sache s2 += s1; 56413985Sache if (s2 > 60) { 56513985Sache m2 += s2 / 60; 56613985Sache s2 %= 60; 56713985Sache } 56813985Sache 56913985Sache m2 += m1; 57013985Sache } else { 57113985Sache tr2 = n; 57213989Sache if (msf) { 57313989Sache m2 = toc_buffer[n].addr.msf.minute; 57413989Sache s2 = toc_buffer[n].addr.msf.second; 57513989Sache f2 = toc_buffer[n].addr.msf.frame; 57613989Sache } else { 57713989Sache lba2msf(ntohl(toc_buffer[n].addr.lba), 57813989Sache &tm, &ts, &tf); 57913989Sache m2 = tm; 58013989Sache s2 = ts; 58113989Sache f2 = tf; 58213989Sache } 58313985Sache } 58413985Sache } else if (tr2 > n) { 58513985Sache tr2 = n; 58613985Sache m2 = s2 = f2 = 0; 58713985Sache } else { 58813985Sache if (m2 || s2 || f2) 58913985Sache tr2--; 59013989Sache if (msf) { 59113989Sache tm = toc_buffer[tr2].addr.msf.minute; 59213989Sache ts = toc_buffer[tr2].addr.msf.second; 59313989Sache tf = toc_buffer[tr2].addr.msf.frame; 59413989Sache } else 59513989Sache lba2msf(ntohl(toc_buffer[tr2].addr.lba), 59613989Sache &tm, &ts, &tf); 59713989Sache f2 += tf; 59813985Sache if (f2 >= 75) { 59913985Sache s2 += f2 / 75; 60013985Sache f2 %= 75; 60113985Sache } 60213985Sache 60313989Sache s2 += ts; 60413985Sache if (s2 > 60) { 60513985Sache m2 += s2 / 60; 60613985Sache s2 %= 60; 60713985Sache } 60813985Sache 60913989Sache m2 += tm; 61013985Sache } 61113985Sache 61213989Sache if (msf) { 61313989Sache tm = toc_buffer[n].addr.msf.minute; 61413989Sache ts = toc_buffer[n].addr.msf.second; 61513989Sache tf = toc_buffer[n].addr.msf.frame; 61613989Sache } else 61713989Sache lba2msf(ntohl(toc_buffer[n].addr.lba), 61813989Sache &tm, &ts, &tf); 61913985Sache if ((tr2 < n) 62013989Sache && ((m2 > tm) 62113989Sache || ((m2 == tm) 62213989Sache && ((s2 > ts) 62313989Sache || ((s2 == ts) 62413989Sache && (f2 > tf)))))) { 62513985Sache printf ("The playing time of the disc is not that long.\n"); 62613985Sache return (0); 62713985Sache } 62813985Sache return (play_msf (m1, s1, f1, m2, s2, f2)); 62913985Sache 63013985SacheTry_Absolute_Timed_Addresses: 63113985Sache if (6 != sscanf (arg, "%d:%d.%d%d:%d.%d", 63213985Sache &m1, &s1, &f1, &m2, &s2, &f2) && 63310099Sjkh 5 != sscanf (arg, "%d:%d.%d%d:%d", &m1, &s1, &f1, &m2, &s2) && 63410099Sjkh 5 != sscanf (arg, "%d:%d%d:%d.%d", &m1, &s1, &m2, &s2, &f2) && 63510099Sjkh 3 != sscanf (arg, "%d:%d.%d", &m1, &s1, &f1) && 63610099Sjkh 4 != sscanf (arg, "%d:%d%d:%d", &m1, &s1, &m2, &s2) && 63710099Sjkh 2 != sscanf (arg, "%d:%d", &m1, &s1)) 63813985Sache goto Clean_up; 63913985Sache 64010099Sjkh if (m2 == 0) { 64113989Sache if (msf) { 64213989Sache m2 = toc_buffer[n].addr.msf.minute; 64313989Sache s2 = toc_buffer[n].addr.msf.second; 64413989Sache f2 = toc_buffer[n].addr.msf.frame; 64513989Sache } else { 64613989Sache lba2msf(ntohl(toc_buffer[n].addr.lba), 64713989Sache &tm, &ts, &tf); 64813989Sache m2 = tm; 64913989Sache s2 = ts; 65013989Sache f2 = tf; 65113989Sache } 65210099Sjkh } 65310099Sjkh return play_msf (m1, s1, f1, m2, s2, f2); 65410099Sjkh } 65510099Sjkh 65610099Sjkh /* 65710099Sjkh * Play track trk1 [ .idx1 ] [ trk2 [ .idx2 ] ] 65810099Sjkh */ 65910099Sjkh if (4 != sscanf (arg, "%d.%d%d.%d", &start, &istart, &end, &iend) && 66010099Sjkh 3 != sscanf (arg, "%d.%d%d", &start, &istart, &end) && 66110099Sjkh 3 != sscanf (arg, "%d%d.%d", &start, &end, &iend) && 66210099Sjkh 2 != sscanf (arg, "%d.%d", &start, &istart) && 66310099Sjkh 2 != sscanf (arg, "%d%d", &start, &end) && 66410099Sjkh 1 != sscanf (arg, "%d", &start)) 66513985Sache goto Clean_up; 66613985Sache 66710099Sjkh if (end == 0) 66810099Sjkh end = n; 66913985Sache return (play_track (start, istart, end, iend)); 67013985Sache 67113985SacheClean_up: 67229103Scharnier warnx("invalid command arguments"); 67313985Sache return (0); 67410099Sjkh} 67510099Sjkh 67610099Sjkhchar *strstatus (int sts) 67710099Sjkh{ 67810099Sjkh switch (sts) { 67910099Sjkh case ASTS_INVALID: return ("invalid"); 68010099Sjkh case ASTS_PLAYING: return ("playing"); 68110099Sjkh case ASTS_PAUSED: return ("paused"); 68210099Sjkh case ASTS_COMPLETED: return ("completed"); 68310099Sjkh case ASTS_ERROR: return ("error"); 68410099Sjkh case ASTS_VOID: return ("void"); 68510099Sjkh default: return ("??"); 68610099Sjkh } 68710099Sjkh} 68810099Sjkh 68913884Sacheint pstatus (char *arg) 69010099Sjkh{ 69110099Sjkh struct ioc_vol v; 69213888Sache struct ioc_read_subchannel ss; 69313888Sache struct cd_sub_channel_info data; 69413884Sache int rc, trk, m, s, f; 69532782Sjmz int what = 0; 69632782Sjmz char *p; 69710099Sjkh 69832782Sjmz while ((p = strtok(arg, " \t"))) { 69932782Sjmz arg = 0; 70032782Sjmz if (!strncasecmp(p, "audio", strlen(p))) 70132782Sjmz what |= STATUS_AUDIO; 70232782Sjmz else if (!strncasecmp(p, "media", strlen(p))) 70332782Sjmz what |= STATUS_MEDIA; 70432782Sjmz else if (!strncasecmp(p, "volume", strlen(p))) 70532782Sjmz what |= STATUS_VOLUME; 70632782Sjmz else { 70732782Sjmz warnx("invalid command arguments"); 70832782Sjmz return 0; 70932782Sjmz } 71032782Sjmz } 71132782Sjmz if (!what) 71232782Sjmz what = STATUS_AUDIO|STATUS_MEDIA|STATUS_VOLUME; 71332782Sjmz if (what & STATUS_AUDIO) { 71432782Sjmz rc = status (&trk, &m, &s, &f); 71532782Sjmz if (rc >= 0) 71610099Sjkh if (verbose) 71732782Sjmz printf ("Audio status = %d<%s>, current track = %d, current position = %d:%02d.%02d\n", 71832782Sjmz rc, strstatus (rc), trk, m, s, f); 71910099Sjkh else 72032782Sjmz printf ("%d %d %d:%02d.%02d\n", rc, trk, m, s, f); 72132782Sjmz else 72213888Sache printf ("No current status info available\n"); 72332782Sjmz } 72432782Sjmz if (what & STATUS_MEDIA) { 72532782Sjmz bzero (&ss, sizeof (ss)); 72632782Sjmz ss.data = &data; 72732782Sjmz ss.data_len = sizeof (data); 72832782Sjmz ss.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 72932782Sjmz ss.data_format = CD_MEDIA_CATALOG; 73032782Sjmz rc = ioctl (fd, CDIOCREADSUBCHANNEL, (char *) &ss); 73132782Sjmz if (rc >= 0) { 73213889Sache printf("Media catalog is %sactive", 73332782Sjmz ss.data->what.media_catalog.mc_valid ? "": "in"); 73416736Sache if (ss.data->what.media_catalog.mc_valid && 73516736Sache ss.data->what.media_catalog.mc_number[0]) 73632782Sjmz printf(", number \"%.15s\"", 73732782Sjmz ss.data->what.media_catalog.mc_number); 73813889Sache putchar('\n'); 73932782Sjmz } else 74013888Sache printf("No media catalog info available\n"); 74132782Sjmz } 74232782Sjmz if (what & STATUS_VOLUME) { 74332782Sjmz rc = ioctl (fd, CDIOCGETVOL, &v); 74432782Sjmz if (rc >= 0) 74510099Sjkh if (verbose) 74632782Sjmz printf ("Left volume = %d, right volume = %d\n", 74732782Sjmz v.vol[0], v.vol[1]); 74810099Sjkh else 74932782Sjmz printf ("%d %d\n", v.vol[0], v.vol[1]); 75032782Sjmz else 75113888Sache printf ("No volume level info available\n"); 75232782Sjmz } 75313884Sache return(0); 75413884Sache} 75510099Sjkh 75663091Sjoe/* 75763091Sjoe * dbprog_sum 75863091Sjoe * Convert an integer to its text string representation, and 75963091Sjoe * compute its checksum. Used by dbprog_discid to derive the 76063091Sjoe * disc ID. 76163091Sjoe * 76263091Sjoe * Args: 76363091Sjoe * n - The integer value. 76463091Sjoe * 76563091Sjoe * Return: 76663091Sjoe * The integer checksum. 76763091Sjoe */ 76863091Sjoestatic int 76963091Sjoedbprog_sum(int n) 77063091Sjoe{ 77163091Sjoe char buf[12], 77263091Sjoe *p; 77363091Sjoe int ret = 0; 77463091Sjoe 77563091Sjoe /* For backward compatibility this algorithm must not change */ 77663091Sjoe sprintf(buf, "%u", n); 77763091Sjoe for (p = buf; *p != '\0'; p++) 77863091Sjoe ret += (*p - '0'); 77963091Sjoe 78063091Sjoe return(ret); 78163091Sjoe} 78263091Sjoe 78363091Sjoe 78463091Sjoe/* 78563091Sjoe * dbprog_discid 78663091Sjoe * Compute a magic disc ID based on the number of tracks, 78763091Sjoe * the length of each track, and a checksum of the string 78863091Sjoe * that represents the offset of each track. 78963091Sjoe * 79063091Sjoe * Args: 79163091Sjoe * s - Pointer to the curstat_t structure. 79263091Sjoe * 79363091Sjoe * Return: 79463091Sjoe * The integer disc ID. 79563091Sjoe */ 79663091Sjoestatic u_int 79763091Sjoedbprog_discid() 79863091Sjoe{ 79963091Sjoe struct ioc_toc_header h; 80063091Sjoe int rc; 80163091Sjoe int i, ntr, 80263091Sjoe t = 0, 80363091Sjoe n = 0; 80463091Sjoe 80563091Sjoe rc = ioctl (fd, CDIOREADTOCHEADER, &h); 80663091Sjoe if (rc < 0) 80763091Sjoe return 0; 80863091Sjoe ntr = h.ending_track - h.starting_track + 1; 80963091Sjoe i = msf; 81063091Sjoe msf = 1; 81163091Sjoe rc = read_toc_entrys ((ntr + 1) * sizeof (struct cd_toc_entry)); 81263091Sjoe msf = i; 81363091Sjoe if (rc < 0) 81463091Sjoe return 0; 81563091Sjoe /* For backward compatibility this algorithm must not change */ 81663091Sjoe for (i = 0; i < ntr; i++) { 81763091Sjoe#define TC_MM(a) toc_buffer[a].addr.msf.minute 81863091Sjoe#define TC_SS(a) toc_buffer[a].addr.msf.second 81963091Sjoe n += dbprog_sum((TC_MM(i) * 60) + TC_SS(i)); 82063091Sjoe 82163091Sjoe t += ((TC_MM(i+1) * 60) + TC_SS(i+1)) - 82263091Sjoe ((TC_MM(i) * 60) + TC_SS(i)); 82363091Sjoe } 82463091Sjoe 82563091Sjoe return((n % 0xff) << 24 | t << 8 | ntr); 82663091Sjoe} 82763091Sjoe 82863091Sjoeint cdid () 82963091Sjoe{ 83063091Sjoe u_int id; 83163091Sjoe 83263091Sjoe id = dbprog_discid(); 83363091Sjoe if (id) 83463091Sjoe { 83563091Sjoe if (verbose) 83663091Sjoe printf ("CDID="); 83763091Sjoe printf ("%08x\n",id); 83863091Sjoe } 83963091Sjoe return id ? 0 : 1; 84063091Sjoe} 84163091Sjoe 84213884Sacheint info (char *arg) 84313884Sache{ 84413884Sache struct ioc_toc_header h; 84513884Sache int rc, i, n; 84613884Sache 84710099Sjkh rc = ioctl (fd, CDIOREADTOCHEADER, &h); 84813888Sache if (rc >= 0) { 84910099Sjkh if (verbose) 85010099Sjkh printf ("Starting track = %d, ending track = %d, TOC size = %d bytes\n", 85110099Sjkh h.starting_track, h.ending_track, h.len); 85210099Sjkh else 85310099Sjkh printf ("%d %d %d\n", h.starting_track, 85410099Sjkh h.ending_track, h.len); 85513888Sache } else { 85629103Scharnier warn("getting toc header"); 85710099Sjkh return (rc); 85810099Sjkh } 85910099Sjkh 86010099Sjkh n = h.ending_track - h.starting_track + 1; 86110099Sjkh rc = read_toc_entrys ((n + 1) * sizeof (struct cd_toc_entry)); 86210099Sjkh if (rc < 0) 86310099Sjkh return (rc); 86413985Sache 86510099Sjkh if (verbose) { 86610099Sjkh printf ("track start duration block length type\n"); 86710099Sjkh printf ("-------------------------------------------------\n"); 86810099Sjkh } 86913985Sache 87010099Sjkh for (i = 0; i < n; i++) { 87110099Sjkh printf ("%5d ", toc_buffer[i].track); 87210099Sjkh prtrack (toc_buffer + i, 0); 87310099Sjkh } 87413867Sache printf ("%5d ", toc_buffer[n].track); 87510099Sjkh prtrack (toc_buffer + n, 1); 87610099Sjkh return (0); 87710099Sjkh} 87810099Sjkh 87913985Sachevoid lba2msf (unsigned long lba, u_char *m, u_char *s, u_char *f) 88010099Sjkh{ 88113985Sache lba += 150; /* block start offset */ 88213985Sache lba &= 0xffffff; /* negative lbas use only 24 bits */ 88310099Sjkh *m = lba / (60 * 75); 88410099Sjkh lba %= (60 * 75); 88510099Sjkh *s = lba / 75; 88610099Sjkh *f = lba % 75; 88710099Sjkh} 88810099Sjkh 88913985Sacheunsigned int msf2lba (u_char m, u_char s, u_char f) 89010099Sjkh{ 89110099Sjkh return (((m * 60) + s) * 75 + f) - 150; 89210099Sjkh} 89310099Sjkh 89410099Sjkhvoid prtrack (struct cd_toc_entry *e, int lastflag) 89510099Sjkh{ 89610099Sjkh int block, next, len; 89710099Sjkh u_char m, s, f; 89810099Sjkh 89913884Sache if (msf) { 90013884Sache /* Print track start */ 90113884Sache printf ("%2d:%02d.%02d ", e->addr.msf.minute, 90213884Sache e->addr.msf.second, e->addr.msf.frame); 90310099Sjkh 90413884Sache block = msf2lba (e->addr.msf.minute, e->addr.msf.second, 90513884Sache e->addr.msf.frame); 90613884Sache } else { 90713884Sache block = ntohl(e->addr.lba); 90813884Sache lba2msf(block, &m, &s, &f); 90913884Sache /* Print track start */ 91013884Sache printf ("%2d:%02d.%02d ", m, s, f); 91113884Sache } 91210099Sjkh if (lastflag) { 91310099Sjkh /* Last track -- print block */ 91410099Sjkh printf (" - %6d - -\n", block); 91510099Sjkh return; 91610099Sjkh } 91710099Sjkh 91813884Sache if (msf) 91913884Sache next = msf2lba (e[1].addr.msf.minute, e[1].addr.msf.second, 92013884Sache e[1].addr.msf.frame); 92113884Sache else 92213884Sache next = ntohl(e[1].addr.lba); 92310099Sjkh len = next - block; 92410099Sjkh lba2msf (len, &m, &s, &f); 92510099Sjkh 92610099Sjkh /* Print duration, block, length, type */ 92710099Sjkh printf ("%2d:%02d.%02d %6d %6d %5s\n", m, s, f, block, len, 92813985Sache (e->control & 4) ? "data" : "audio"); 92910099Sjkh} 93010099Sjkh 93110099Sjkhint play_track (int tstart, int istart, int tend, int iend) 93210099Sjkh{ 93310099Sjkh struct ioc_play_track t; 93410099Sjkh 93510099Sjkh t.start_track = tstart; 93610099Sjkh t.start_index = istart; 93710099Sjkh t.end_track = tend; 93810099Sjkh t.end_index = iend; 93913985Sache 94010099Sjkh return ioctl (fd, CDIOCPLAYTRACKS, &t); 94110099Sjkh} 94210099Sjkh 94310099Sjkhint play_blocks (int blk, int len) 94410099Sjkh{ 94513985Sache struct ioc_play_blocks t; 94610099Sjkh 94710099Sjkh t.blk = blk; 94810099Sjkh t.len = len; 94913985Sache 95010099Sjkh return ioctl (fd, CDIOCPLAYBLOCKS, &t); 95110099Sjkh} 95210099Sjkh 95313985Sacheint setvol (int left, int right) 95410099Sjkh{ 95513985Sache struct ioc_vol v; 95610099Sjkh 95713985Sache v.vol[0] = left; 95813985Sache v.vol[1] = right; 95910099Sjkh v.vol[2] = 0; 96010099Sjkh v.vol[3] = 0; 96113985Sache 96210099Sjkh return ioctl (fd, CDIOCSETVOL, &v); 96310099Sjkh} 96410099Sjkh 96510099Sjkhint read_toc_entrys (int len) 96610099Sjkh{ 96710099Sjkh struct ioc_read_toc_entry t; 96810099Sjkh 96913884Sache t.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 97013737Sache t.starting_track = 0; 97110099Sjkh t.data_len = len; 97210099Sjkh t.data = toc_buffer; 97313985Sache 97413985Sache return (ioctl (fd, CDIOREADTOCENTRYS, (char *) &t)); 97510099Sjkh} 97610099Sjkh 97710099Sjkhint play_msf (int start_m, int start_s, int start_f, 97813985Sache int end_m, int end_s, int end_f) 97910099Sjkh{ 98013985Sache struct ioc_play_msf a; 98110099Sjkh 98210099Sjkh a.start_m = start_m; 98310099Sjkh a.start_s = start_s; 98410099Sjkh a.start_f = start_f; 98510099Sjkh a.end_m = end_m; 98610099Sjkh a.end_s = end_s; 98710099Sjkh a.end_f = end_f; 98813985Sache 98910099Sjkh return ioctl (fd, CDIOCPLAYMSF, (char *) &a); 99010099Sjkh} 99110099Sjkh 99210099Sjkhint status (int *trk, int *min, int *sec, int *frame) 99310099Sjkh{ 99410099Sjkh struct ioc_read_subchannel s; 99510099Sjkh struct cd_sub_channel_info data; 99613884Sache u_char mm, ss, ff; 99710099Sjkh 99810099Sjkh bzero (&s, sizeof (s)); 99910099Sjkh s.data = &data; 100010099Sjkh s.data_len = sizeof (data); 100113884Sache s.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 100210099Sjkh s.data_format = CD_CURRENT_POSITION; 100313985Sache 100410099Sjkh if (ioctl (fd, CDIOCREADSUBCHANNEL, (char *) &s) < 0) 100510099Sjkh return -1; 100613985Sache 100710099Sjkh *trk = s.data->what.position.track_number; 100813884Sache if (msf) { 100913884Sache *min = s.data->what.position.reladdr.msf.minute; 101013884Sache *sec = s.data->what.position.reladdr.msf.second; 101113884Sache *frame = s.data->what.position.reladdr.msf.frame; 101213884Sache } else { 101313884Sache lba2msf(ntohl(s.data->what.position.reladdr.lba), 101413884Sache &mm, &ss, &ff); 101513884Sache *min = mm; 101613884Sache *sec = ss; 101713884Sache *frame = ff; 101813884Sache } 101913985Sache 102010099Sjkh return s.data->header.audio_status; 102110099Sjkh} 102210099Sjkh 102350039Smdoddconst char * 102450039Smdoddcdcontrol_prompt() 102510099Sjkh{ 102650039Smdodd return ("cdcontrol> "); 102750039Smdodd} 102850039Smdodd 102950039Smdoddchar * 103050039Smdoddinput (int *cmd) 103150039Smdodd{ 103250039Smdodd#define MAXLINE 80 103350039Smdodd static EditLine *el = NULL; 103450039Smdodd static History *hist = NULL; 103550039Smdodd static char buf[MAXLINE]; 103650039Smdodd int num = 0; 103750071Smdodd int len; 103850039Smdodd const char *bp = NULL; 103910099Sjkh char *p; 104010099Sjkh 104110099Sjkh do { 104250039Smdodd if (verbose) { 104350039Smdodd if (!el) { 104450039Smdodd el = el_init("cdcontrol", stdin, stdout); 104550039Smdodd hist = history_init(); 104650039Smdodd history(hist, H_EVENT, 100); 104750039Smdodd el_set(el, EL_HIST, history, hist); 104850039Smdodd el_set(el, EL_EDITOR, "emacs"); 104950039Smdodd el_set(el, EL_PROMPT, cdcontrol_prompt); 105050039Smdodd el_set(el, EL_SIGNAL, 1); 105150042Smdodd el_source(el, NULL); 105250039Smdodd } 105363070Smckay if ((bp = el_gets(el, &num)) == NULL || num == 0) { 105463070Smckay *cmd = CMD_QUIT; 105563070Smckay fprintf (stderr, "\r\n"); 105650039Smdodd return (0); 105763070Smckay } 105850039Smdodd 105950071Smdodd len = (num > MAXLINE) ? MAXLINE : num; 106050071Smdodd memcpy(buf, bp, len); 106150071Smdodd buf[len] = 0; 106250039Smdodd history(hist, H_ENTER, bp); 106350039Smdodd#undef MAXLINE 106450039Smdodd 106550039Smdodd } else { 106650039Smdodd if (! fgets (buf, sizeof (buf), stdin)) { 106750039Smdodd *cmd = CMD_QUIT; 106850039Smdodd fprintf (stderr, "\r\n"); 106950039Smdodd return (0); 107050039Smdodd } 107110099Sjkh } 107210099Sjkh p = parse (buf, cmd); 107310099Sjkh } while (! p); 107410099Sjkh return (p); 107510099Sjkh} 107610099Sjkh 107710099Sjkhchar *parse (char *buf, int *cmd) 107810099Sjkh{ 107910099Sjkh struct cmdtab *c; 108010099Sjkh char *p; 108110099Sjkh int len; 108210099Sjkh 108313985Sache for (p=buf; isspace (*p); p++) 108413985Sache continue; 108510099Sjkh 108613985Sache if (isdigit (*p) || (p[0] == '#' && isdigit (p[1]))) { 108713985Sache *cmd = CMD_PLAY; 108813985Sache return (p); 108913985Sache } 109010099Sjkh 109113985Sache for (buf = p; *p && ! isspace (*p); p++) 109213985Sache continue; 109313985Sache 109413985Sache len = p - buf; 109510099Sjkh if (! len) 109610099Sjkh return (0); 109713985Sache 109813985Sache if (*p) { /* It must be a spacing character! */ 109913985Sache char *q; 110013985Sache 110113985Sache *p++ = 0; 110213985Sache for (q=p; *q && *q != '\n' && *q != '\r'; q++) 110313985Sache continue; 110413985Sache *q = 0; 110513985Sache } 110613985Sache 110710099Sjkh *cmd = -1; 110810099Sjkh for (c=cmdtab; c->name; ++c) { 110913985Sache /* Is it an exact match? */ 111013985Sache if (! strcasecmp (buf, c->name)) { 111113985Sache *cmd = c->command; 111213985Sache break; 111313985Sache } 111413985Sache 111513985Sache /* Try short hand forms then... */ 111613985Sache if (len >= c->min && ! strncasecmp (buf, c->name, len)) { 111713985Sache if (*cmd != -1 && *cmd != c->command) { 111829103Scharnier warnx("ambiguous command"); 111913985Sache return (0); 112013985Sache } 112110099Sjkh *cmd = c->command; 112213985Sache } 112313985Sache } 112410099Sjkh 112510099Sjkh if (*cmd == -1) { 112629103Scharnier warnx("invalid command, enter ``help'' for commands"); 112710099Sjkh return (0); 112810099Sjkh } 112913985Sache 113013985Sache while (isspace (*p)) 113113985Sache p++; 113210099Sjkh return p; 113310099Sjkh} 113410099Sjkh 113510099Sjkhint open_cd () 113610099Sjkh{ 113754164Sjoe char devbuf[MAXPATHLEN]; 113810099Sjkh 113910099Sjkh if (fd > -1) 114010099Sjkh return (1); 114113985Sache 114254164Sjoe if (*cdname == '/') { 114354164Sjoe snprintf (devbuf, MAXPATHLEN, "%s", cdname); 114461105Smsmith } else { 114569793Sobrien snprintf (devbuf, MAXPATHLEN, "%s%s", _PATH_DEV, cdname); 114654164Sjoe } 114713985Sache 114810099Sjkh fd = open (devbuf, O_RDONLY); 114913985Sache 115010099Sjkh if (fd < 0 && errno == ENOENT) { 115113985Sache strcat (devbuf, DEFAULT_CD_PARTITION); 115210099Sjkh fd = open (devbuf, O_RDONLY); 115310099Sjkh } 115413985Sache 115510099Sjkh if (fd < 0) { 115613985Sache if (errno == ENXIO) { 115713985Sache /* ENXIO has an overloaded meaning here. 115813985Sache * The original "Device not configured" should 115913985Sache * be interpreted as "No disc in drive %s". */ 116029103Scharnier warnx("no disc in drive %s", devbuf); 116113985Sache return (0); 116210099Sjkh } 116329103Scharnier err(1, "%s", devbuf); 116410099Sjkh } 116510099Sjkh return (1); 116610099Sjkh} 1167