home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #27 / NN_1992_27.iso / spool / alt / sources / 2527 / cdinfo.c next >
Encoding:
C/C++ Source or Header  |  1992-11-15  |  17.3 KB  |  843 lines

  1. /*
  2.  * @(#)cdinfo.c    1.80    11/15/92
  3.  *
  4.  * Get information about a CD.
  5.  */
  6. static char *ident = "@(#)cdinfo.c    1.80 11/15/92";
  7.  
  8. #include <errno.h>
  9. #include <stdio.h>
  10. #include <sys/types.h>
  11. #include "struct.h"
  12.  
  13. void *calloc(), *malloc(), *realloc(), print_cdinfo(), wipe_cdinfo();
  14. char *strchr(), *getenv();
  15.  
  16. struct play *playlist = NULL;
  17. struct cdinfo thiscd, *cd = &thiscd;
  18.  
  19. int    cur_track = -1;    /* Current track number, starting at 1 */
  20. int    cur_index = 0;    /* Current index mark */
  21. int    cur_lasttrack = 999;    /* Last track to play in current chunk */
  22. int    cur_firsttrack = 0;    /* First track of current chunk */
  23. int    cur_pos_abs;    /* Current absolute position in seconds */
  24. int    cur_frame;    /* Current frame number */
  25. int    cur_pos_rel;    /* Current track-relative position in seconds */
  26. int    cur_tracklen;    /* Length in seconds of current track */
  27. int    cur_cdlen;    /* Length in seconds of entire CD */
  28. int    cur_ntracks;    /* Number of tracks on CD (= tracks + sections) */
  29. int    cur_nsections;    /* Number of sections currently defined */
  30. int    cur_cdmode;    /* CD play mode (1=play, 3=pause, 4=stop, 5=eject) */
  31. int    cur_listno;    /* Current index into the play list, if playing */
  32. char *    cur_artist;    /* Name of current CD's artist */
  33. char *    cur_cdname;    /* Album name */
  34. char *    cur_trackname;    /* Take a guess */
  35. char    cur_contd;    /* Continued flag */
  36. char    cur_avoid;    /* Avoid flag */
  37.  
  38. int    exit_on_eject = 0;
  39.  
  40. extern int cur_stopmode;
  41. extern int info_modified;
  42.  
  43. /*
  44.  * insert_trackinfo()
  45.  *
  46.  * Add a new track to the CD info structure.  Pass the position of the new
  47.  * entry in the track list -- 0 will make this the first track, 1 the second,
  48.  * etc.  The new entry will be zeroed out.
  49.  */
  50. void
  51. insert_trackinfo(num)
  52.     int    num;
  53. {
  54.     struct trackinfo *newtrk;
  55.  
  56.     /* Easy case: the list is empty */
  57.     if (cd->trk == NULL)
  58.         if ((cd->trk = (struct trackinfo *) calloc(1,
  59.                         sizeof(*newtrk))) == NULL)
  60.         {
  61. nomem:
  62.             perror("insert_trackinfo");
  63.             exit(1);
  64.         }
  65.         else
  66.             return;
  67.  
  68.     /* Stick the new entry in cd->trk[]. */
  69.     if ((newtrk = (struct trackinfo *) malloc(sizeof(*newtrk) *
  70.                         (cur_ntracks + 1))) == NULL)
  71.         goto nomem;
  72.  
  73.     if (num)
  74.         memcpy(newtrk, cd->trk, sizeof(*newtrk) * num);
  75.     memset(&newtrk[num], 0, sizeof(*newtrk));
  76.     if (num < cur_ntracks)
  77.         memcpy(&newtrk[num + 1], &cd->trk[num], sizeof(*newtrk) *
  78.             (cur_ntracks - num));
  79.  
  80.     free(cd->trk);
  81.     cd->trk = newtrk;
  82. }
  83.  
  84. /*
  85.  * split_trackinfo()
  86.  *
  87.  * Split a track in two at a particular position (absolute, in frames).  All
  88.  * internal data structures and variables will be adjusted to the new
  89.  * numbering scheme.  Pass in the track number (>=1) to split, which is also
  90.  * the index into cd->trk[] of the new entry.
  91.  *
  92.  * If pos is within 1 second of the start of another track, the split fails.
  93.  *
  94.  * Returns 1 on success, 0 if the track couldn't be inserted.
  95.  *
  96.  * Note: updating user interface elements is up to the caller.
  97.  */
  98. split_trackinfo(pos)
  99.     int    pos;
  100. {
  101.     int    i, l, num;
  102.  
  103.     if (pos < cd->trk[0].start)
  104.         return (0);
  105.  
  106.     /* First find the appropriate track. */
  107.     for (num = 0; num < cur_ntracks; num++)
  108.         if (cd->trk[num].start - 75 < pos &&
  109.                         cd->trk[num].start + 75 > pos)
  110.             return (0);
  111.         else if (cd->trk[num].start > pos)
  112.             break;
  113.     if (num == 0)
  114.         return (0);
  115.  
  116.     /* Insert the new entry into the track array. */
  117.     insert_trackinfo(num);
  118.  
  119.     /* Update the easy variables. */
  120.     if (cur_track > num)
  121.         cur_track++;
  122.     if (cur_firsttrack > num)
  123.         cur_firsttrack++;
  124.     if (cur_lasttrack > num)
  125.         cur_lasttrack++;
  126.  
  127.     /* Update the user-defined playlists. */
  128.     if (cd->lists != NULL)
  129.         for (l = 0; cd->lists[l].name != NULL; l++)
  130.             if (cd->lists[l].list != NULL)
  131.                 for (i = 0; cd->lists[l].list[i]; i++)
  132.                     if (cd->lists[l].list[i] > num)
  133.                         cd->lists[l].list[i]++;
  134.  
  135.     /* Update the internal playlist. */
  136.     if (playlist != NULL)
  137.         for (i = 0; playlist[i].start; i++)
  138.         {
  139.             if (playlist[i].start > num)
  140.                 playlist[i].start++;
  141.             if (playlist[i].end > num)
  142.                 playlist[i].end++;
  143.         }
  144.     
  145.     /* Now adjust the information in cd->trk[]. */
  146.     cd->trk[num].start = pos;
  147.     if (num == cur_ntracks)
  148.         cd->trk[num].length = cur_cdlen - pos / 75;
  149.     else
  150.         cd->trk[num].length = (cd->trk[num + 1].start - pos) / 75;
  151.     cd->trk[num - 1].length -= cd->trk[num].length;
  152.     if (cur_track == num)
  153.         cur_tracklen -= cd->trk[num].length;
  154.     cd->trk[num].track = cd->trk[num - 1].track;
  155.     cd->trk[num].data = cd->trk[num - 1].data;
  156.     cd->trk[num].contd = 1;
  157.     cd->trk[num].volume = cd->trk[num - 1].volume;
  158.  
  159.     if (cd->trk[num - 1].section == 0)
  160.         cd->trk[num - 1].section = 1;
  161.     cd->trk[num].section = cd->trk[num - 1].section + 1;
  162.  
  163.     cur_ntracks++;
  164.     cur_nsections++;
  165.  
  166.     for (i = num + 1; i < cur_ntracks; i++)
  167.         if (cd->trk[i].track == cd->trk[num].track)
  168.             cd->trk[i].section++;
  169.     
  170.     return (1);
  171. }
  172.  
  173. /*
  174.  * remove_trackinfo()
  175.  *
  176.  * Remove a track's internal data.  This is similar to split_trackinfo()
  177.  * above, but simpler.  A track's initial section can't be removed.  Track
  178.  * numbers start at 0.
  179.  *
  180.  * Returns 1 on success, 0 on failure.
  181.  */
  182. remove_trackinfo(num)
  183.     int    num;
  184. {
  185.     int    i, l;
  186.  
  187.     if (num < 1 || num >= cur_ntracks || cd->trk[num].section < 2)
  188.         return (0);
  189.     
  190.     cd->trk[num - 1].length += cd->trk[num].length;
  191.  
  192.     for (i = num; i < cur_ntracks - 1; i++)
  193.         memcpy(&cd->trk[i], &cd->trk[i + 1], sizeof(cd->trk[0]));
  194.  
  195.     if (cur_track > num)
  196.         cur_track--;
  197.     if (cur_firsttrack > num)
  198.         cur_firsttrack--;
  199.     if (cur_lasttrack > num)
  200.         cur_lasttrack--;
  201.     
  202.     /* Update the user-defined playlists. */
  203.     if (cd->lists != NULL)
  204.         for (l = 0; cd->lists[l].name != NULL; l++)
  205.             if (cd->lists[l].list != NULL)
  206.                 for (i = 0; cd->lists[l].list[i]; i++)
  207.                     if (cd->lists[l].list[i] > num)
  208.                         cd->lists[l].list[i]--;
  209.     
  210.     /* Update the internal playlist. */
  211.     if (playlist != NULL)
  212.         for (i = 0; playlist[i].start; i++)
  213.         {
  214.             if (playlist[i].start > num)
  215.                 playlist[i].start--;
  216.             if (playlist[i].end > num)
  217.                 playlist[i].end--;
  218.         }
  219.     
  220.     cur_ntracks--;
  221.     cur_nsections--;
  222.  
  223.     /* Update the section numbers for this track. */
  224.     if (cd->trk[num - 1].track != cd->trk[num].track)
  225.     {
  226.         if (cd->trk[num - 1].section == 1)
  227.             cd->trk[num - 1].section = 0;
  228.     }
  229.     else
  230.         for (i = num; i < cur_ntracks; i++)
  231.             if (cd->trk[i].track == cd->trk[num - 1].track)
  232.                 cd->trk[i].section--;
  233.  
  234.     return (1);
  235. }
  236.  
  237. /*
  238.  * listentry()
  239.  *
  240.  * Return a scrolling list entry.
  241.  *
  242.  * XXX - should count half-spaces to make entries line up when sections
  243.  *       are present
  244.  */
  245. char *
  246. listentry(num)
  247.     int    num;
  248. {
  249.     static char    buf[600];
  250.     char        *name, tracknum[20];
  251.     int        digits;
  252.  
  253.     if (num >= 0 && num < cur_ntracks)
  254.     {
  255.         digits = cd->trk[num].track < 10 ? 3 : 2;
  256.         name = cd->trk[num].songname ? cd->trk[num].songname : "";
  257.  
  258.         if (cur_nsections)
  259.             if (cd->trk[num].section)
  260.                 sprintf(tracknum, "%*d.%d", digits,
  261.                     cd->trk[num].track,
  262.                     cd->trk[num].section);
  263.             else
  264.                 sprintf(tracknum, "%*d   ", digits,
  265.                     cd->trk[num].track);
  266.         else
  267.             sprintf(tracknum, "%*d", digits, cd->trk[num].track);
  268.  
  269.         if (cd->trk[num].data)
  270.             sprintf(buf, "%s) %3dMB %s", tracknum,
  271.                 cd->trk[num].length / 1024, name);
  272.         else
  273.             sprintf(buf, "%s) %02d:%02d %s", tracknum,
  274.                 cd->trk[num].length / 60,
  275.                 cd->trk[num].length % 60, name);
  276.  
  277.         return (buf);
  278.     }
  279.     else
  280.         return (NULL);
  281. }
  282.  
  283. /*
  284.  * trackname()
  285.  *
  286.  * Return a track's name.
  287.  */
  288. char *
  289. trackname(num)
  290.     int    num;
  291. {
  292.     if (num >= 0 && num < cur_ntracks)
  293.         if (cd->trk[num].songname)
  294.             return (cd->trk[num].songname);
  295.         else
  296.             return ("");
  297.     else
  298.         return (NULL);
  299. }
  300.  
  301. /*
  302.  * tracklen()
  303.  *
  304.  * Return a track's length in seconds.
  305.  */
  306. tracklen(num)
  307.     int    num;
  308. {
  309.     if (cd != NULL && num >= 0 && num < cur_ntracks)
  310.         return (cd->trk[num].length);
  311.     else
  312.         return (0);
  313. }
  314.  
  315. /*
  316.  * get_default_volume()
  317.  *
  318.  * Return the default volume (0-32, 0=none) for the CD or a track.
  319.  */
  320. get_default_volume(track)
  321.     int    track;
  322. {
  323.     if (! track)
  324.         return (cd->volume);
  325.     else if (track <= cur_ntracks)
  326.         return (cd->trk[track - 1].volume);
  327.     else
  328.         return (0);
  329. }
  330.  
  331. /*
  332.  * get_contd()
  333.  *
  334.  * Return the contd value for a track.
  335.  */
  336. get_contd(num)
  337.     int    num;
  338. {
  339.     if (num >= 0 && num < cur_ntracks)
  340.         return (cd->trk[num].contd);
  341.     else
  342.         return (NULL);
  343. }
  344.  
  345. /*
  346.  * get_avoid()
  347.  *
  348.  * Return the avoid value for a track.
  349.  */
  350. get_avoid(num)
  351.     int    num;
  352. {
  353.     if (num >= 0 && num < cur_ntracks)
  354.         return (cd->trk[num].avoid);
  355.     else
  356.         return (NULL);
  357. }
  358.  
  359. /*
  360.  * get_autoplay()
  361.  *
  362.  * Is autoplay set on this disc?
  363.  */
  364. get_autoplay()
  365. {
  366.     return (cd->autoplay);
  367. }
  368.  
  369. /*
  370.  * get_playmode()
  371.  *
  372.  * Return the default playmode for the CD.
  373.  */
  374. get_playmode()
  375. {
  376.     return (cd->playmode);
  377. }
  378.  
  379. /*
  380.  * get_runtime()
  381.  *
  382.  * Return the total running time for the current playlist in seconds.
  383.  */
  384. get_runtime()
  385. {
  386.     int    i;
  387.  
  388.     if (playlist == NULL || playlist[0].start == 0 || cur_firsttrack == -1)
  389.         return (cd == NULL ? 0 : cd->length);
  390.  
  391.     for (i = 0; playlist[i].start; i++)
  392.         ;
  393.  
  394.     return (playlist[i].starttime);
  395. }
  396.  
  397. /*
  398.  * default_volume()
  399.  *
  400.  * Set the default volume for the CD or a track.
  401.  */
  402. void
  403. default_volume(track, vol)
  404.     int    track, vol;
  405. {
  406.     if (track == 0)
  407.         cd->volume = vol;
  408.     else if (track <= cur_ntracks)
  409.         cd->trk[track - 1].volume = vol;
  410. }
  411.  
  412. /*
  413.  * Play the next thing on the playlist, if any.
  414.  */
  415. void
  416. play_next_entry()
  417. {
  418.     if (cd == NULL)
  419.         return;
  420.     if (playlist != NULL && playlist[cur_listno].start)
  421.     {
  422.         play_cd(playlist[cur_listno].start, 0,
  423.             playlist[cur_listno].end);
  424.         cur_listno++;
  425.     }
  426.     else
  427.         stop_cd();
  428. }
  429.  
  430. /*
  431.  * Play the next track, following playlists as necessary.
  432.  */
  433. void
  434. play_next_track()
  435. {
  436.     if (cd == NULL)
  437.         return;
  438.  
  439.     /* Is the current playlist entry done?  Move on, if so. */
  440.     if (playlist == NULL || cur_track + 1 == playlist[cur_listno - 1].end)
  441.         play_next_entry();
  442.     else
  443.         play_cd(cur_track + 1, 0, playlist[cur_listno - 1].end);
  444. }
  445.  
  446. /*
  447.  * Play the previous track, hopping around the playlist as necessary.
  448.  */
  449. void
  450. play_prev_track()
  451. {
  452.     if (cd == NULL)
  453.         return;
  454.  
  455.     if (playlist == NULL)
  456.         return;
  457.  
  458.     /* If we're in the middle of this playlist entry, go back one track */
  459.     if (cur_track > playlist[cur_listno - 1].start)
  460.         play_cd(cur_track - 1, 0, playlist[cur_listno - 1].end);
  461.     else
  462.         if (cur_listno > 1)
  463.         {
  464.             cur_listno--;
  465.             play_cd(playlist[cur_listno - 1].end - 1, 0,
  466.                 playlist[cur_listno - 1].end);
  467.         }
  468.         else
  469.             play_cd(playlist[0].start, 0, playlist[0].end);
  470. }
  471.  
  472. /*
  473.  * stash_cdinfo(artist, cdname)
  474.  */
  475. void
  476. stash_cdinfo(artist, cdname, autoplay, playmode)
  477.     char    *artist, *cdname;
  478.     int    autoplay, playmode;
  479. {
  480.     int    listsize, i;
  481.  
  482.     if (cd != NULL)
  483.     {
  484.         if (strcmp(cd->artist, artist))
  485.             info_modified = 1;
  486.         strcpy(cd->artist, artist);
  487.  
  488.         if (strcmp(cd->cdname, cdname))
  489.             info_modified = 1;
  490.         strcpy(cd->cdname, cdname);
  491.  
  492.         if (!!cd->autoplay != !!autoplay)
  493.             info_modified = 1;
  494.         cd->autoplay = autoplay;
  495.  
  496.         if (!!cd->playmode != !!playmode)
  497.             info_modified = 1;
  498.         cd->playmode = playmode;
  499.     }
  500. }
  501.  
  502. /* Free some memory and set a pointer to null. */
  503. void
  504. freeup(x)
  505. void **x;
  506. {
  507.     if (*x != NULL)
  508.     {
  509.         free(*x);
  510.         *x = NULL;
  511.     }
  512. }
  513.  
  514. /*
  515.  * wipe_cdinfo()
  516.  *
  517.  * Clear out all a CD's soft information (presumably in preparation for
  518.  * reloading from the database.)
  519.  */
  520. void
  521. wipe_cdinfo()
  522. {
  523.     struct playlist    *l;
  524.     int        i;
  525.  
  526.     if (cd != NULL)
  527.     {
  528.         cd->artist[0] = cd->cdname[0] = '\0';
  529.         cd->autoplay = cd->playmode = cd->volume = 0;
  530.         cd->whichdb = NULL;
  531.         freeup(&cd->otherrc);
  532.         freeup(&cd->otherdb);
  533.  
  534.         if (thiscd.lists != NULL)
  535.         {
  536.             for (l = thiscd.lists; l->name != NULL; l++)
  537.             {
  538.                 free(l->name);
  539.                 free(l->list);
  540.             }
  541.             freeup(&thiscd.lists);
  542.         }
  543.  
  544.         for (i = 0; i < cur_ntracks; i++)
  545.         {
  546.             freeup(&cd->trk[i].songname);
  547.             freeup(&cd->trk[i].otherrc);
  548.             freeup(&cd->trk[i].otherdb);
  549.             cd->trk[i].avoid = cd->trk[i].contd = 0;
  550.             cd->trk[i].volume = 0;
  551.             if (cd->trk[i].section > 1)
  552.                 remove_trackinfo(i--);
  553.         }
  554.     }
  555. }
  556.  
  557. /*
  558.  * stash_trkinfo(track, songname, contd, avoid)
  559.  *
  560.  * Update information about a track on the current CD.
  561.  */
  562. void
  563. stash_trkinfo(track, songname, contd, avoid)
  564.     int    track, contd, avoid;
  565.     char    *songname;
  566. {
  567.     if (cd != NULL)
  568.     {
  569.         track--;
  570.         if (!!cd->trk[track].contd != !!contd)
  571.             info_modified = 1;
  572.         cd->trk[track].contd = track ? contd : 0;
  573.  
  574.         if (!!cd->trk[track].avoid != !!avoid)
  575.             info_modified = 1;
  576.         cd->trk[track].avoid = avoid;
  577.  
  578.         if ((cd->trk[track].songname == NULL && songname[0]) ||
  579.                 (cd->trk[track].songname != NULL &&
  580.                 strcmp(cd->trk[track].songname, songname)))
  581.         {
  582.             info_modified = 1;
  583.             strmcpy(&cd->trk[track].songname, songname);
  584.         }
  585.     }
  586. }
  587.  
  588. /*
  589.  * new_list()
  590.  *
  591.  * Add a playlist to a CD.
  592.  */
  593. struct playlist *
  594. new_list(cd, listname)
  595.     struct cdinfo    *cd;
  596.     char        *listname;
  597. {
  598.     int    nlists = 0;
  599.     struct playlist *l;
  600.  
  601.     if (cd->lists != NULL)
  602.     {
  603.         for (nlists = 0; cd->lists[nlists].name != NULL; nlists++)
  604.             ;
  605.         l = (struct playlist *)realloc(cd->lists, (nlists + 2) *
  606.             sizeof (struct playlist));
  607.     }
  608.     else
  609.         l = (struct playlist *)malloc(2 * sizeof (struct playlist));
  610.  
  611.     if (l == NULL)
  612.         return (NULL);
  613.  
  614.     l[nlists + 1].name = NULL;
  615.     l[nlists].name = NULL;        /* so strmcpy doesn't free() it */
  616.     strmcpy(&l[nlists].name, listname);
  617.     l[nlists].list = NULL;
  618.     cd->lists = l;
  619.  
  620.     return (&l[nlists]);
  621. }
  622.  
  623. /*
  624.  * make_playlist()
  625.  *
  626.  * Construct a playlist for the current CD.  If we're in shuffle mode, play
  627.  * each non-avoided track once, keeping continued tracks in the right order.
  628.  *
  629.  * If playmode is 2, use playlist number (playmode-2).  XXX should do
  630.  * bounds checking on this, probably.
  631.  *
  632.  * If consecutive tracks are being played, only make one playlist entry for
  633.  * them, so the CD player won't pause between tracks while we wake up.
  634.  */
  635. void
  636. make_playlist(playmode, starttrack)
  637.     int    playmode, starttrack;
  638. {
  639.     int    i, listsize = 0, avoiding = 1, entry = 0, count, track,
  640.         *thislist;
  641.  
  642.     cur_listno = 0;
  643.     if (playlist != NULL)
  644.         free(playlist);
  645.     playlist = malloc(sizeof (*playlist) * (cur_ntracks + 1));
  646.     if (playlist == NULL)
  647.     {
  648.         perror("playlist");
  649.         exit(1);
  650.     }
  651.  
  652.     /* If this is a data-only CD, we can't play it. */
  653.     if ((starttrack && cd->trk[starttrack - 1].data) ||
  654.         (cur_ntracks == 1 && cd->trk[0].data))
  655.     {
  656.         playlist[0].start = 0;
  657.         playlist[0].end = 0;
  658.         playlist[1].start = 0;
  659.         return;
  660.     }
  661.  
  662.     if (playmode == 1)
  663.     {
  664.         char *done = malloc(cur_ntracks);
  665.  
  666.         if (done == NULL)
  667.         {
  668.             perror("randomizer");
  669.             exit(1);
  670.         }
  671.  
  672.         count = cur_ntracks;
  673.         if (starttrack && cd->trk[starttrack - 1].avoid)
  674.             count++;
  675.         for (i = 0; i < cur_ntracks; i++)
  676.             if (cd->trk[i].contd || cd->trk[i].avoid ||
  677.                 cd->trk[i].data)
  678.             {
  679.                 done[i] = 1;
  680.                 count--;
  681.             }
  682.             else
  683.                 done[i] = 0;
  684.  
  685.         for (i = 0; i < count; i++)
  686.         {
  687.             int end;    /* for readability */
  688.             if (starttrack)
  689.             {
  690.                 track = starttrack - 1;
  691.                 starttrack = 0;
  692.             }
  693.             else
  694.                 while (done[track = rand() % cur_ntracks])
  695.                     ;
  696.  
  697.             playlist[i].start = track + 1;
  698.  
  699.             /* play all subsequent continuation tracks too */
  700.             for (end = track + 1; end < cur_ntracks + 1; end++)
  701.                 if (! cd->trk[end].contd ||
  702.                         cd->trk[end].avoid ||
  703.                         cd->trk[end].data)
  704.                     break;
  705.             playlist[i].end = end + 1;
  706.  
  707.             done[track]++;
  708.         }
  709.         playlist[i].start = 0;
  710.  
  711.         free(done);
  712.     }
  713.     else if (playmode >= 2 && cd->lists && cd->lists[playmode - 2].name)
  714.     {
  715.         count = 2;    /* one terminating entry, and one for start */
  716.         thislist = cd->lists[playmode - 2].list;
  717.  
  718.         for (i = 0; thislist[i]; i++)
  719.             if (thislist[i + 1] != thislist[i] + 1)
  720.                 count++;
  721.  
  722.         if (playlist != NULL)
  723.             free(playlist);
  724.         playlist = malloc(sizeof (*playlist) * count);
  725.         if (playlist == NULL)
  726.         {
  727.             perror("playlist");
  728.             exit(1);
  729.         }
  730.  
  731.         count = 0;
  732.         if (starttrack)
  733.         {
  734.             playlist[0].start = starttrack;
  735.             for (track = 0; thislist[track]; track++)
  736.                 if (starttrack == thislist[track])
  737.                     break;
  738.             if (! thislist[track])
  739.             {
  740.                 playlist[0].end = starttrack + 1;
  741.                 playlist[1].start = thislist[0];
  742.                 count = 1;
  743.                 track = 0;
  744.             }
  745.         }
  746.         else
  747.         {
  748.             playlist[0].start = thislist[0];
  749.             track = 0;
  750.         }
  751.  
  752.         for (i = track; thislist[i]; i++)
  753.             if (thislist[i + 1] != thislist[i] + 1)
  754.             {
  755.                 playlist[count].end = thislist[i] + 1;
  756.                 count++;
  757.                 playlist[count].start = thislist[i + 1];
  758.             }
  759.     }
  760.     else
  761.     {
  762.         for (i = starttrack ? starttrack - 1 : 0; i < cur_ntracks; i++)
  763.             if (avoiding && ! (cd->trk[i].avoid || cd->trk[i].data))
  764.             {
  765.                 playlist[entry].start = i + 1;
  766.                 avoiding = 0;
  767.             }
  768.             else if (! avoiding && (cd->trk[i].avoid ||
  769.                         cd->trk[i].data))
  770.             {
  771.                 playlist[entry].end = i + 1;
  772.                 avoiding = 1;
  773.                 entry++;
  774.             }
  775.         if (! avoiding)
  776.             playlist[entry].end = i + 1;
  777.         playlist[entry + !avoiding].start = 0;
  778.     }
  779.  
  780.     /*
  781.      * Now go through the list, whatever its source, and figure out
  782.      * cumulative starting times for each entry.
  783.      */
  784.     entry = count = 0;
  785.     do {
  786.         playlist[entry].starttime = count;
  787.  
  788.         if (playlist[entry].start)
  789.             for (i = playlist[entry].start; i <
  790.                         playlist[entry].end; i++)
  791.                 count += cd->trk[i - 1].length;
  792.     } while (playlist[entry++].start);
  793. }
  794.  
  795. /*
  796.  * Find a particular track's location in the current playlist.  Sets the
  797.  * appropriate variables (cur_listno, cur_firsttrack, cur_lasttrack).
  798.  */
  799. void
  800. pl_find_track(track)
  801.     int    track;
  802. {
  803.     int    t, i;
  804.  
  805.     if (playlist == NULL)
  806.     {
  807.         fprintf(stderr, "Null playlist!  Huh?\n");
  808.         return;
  809.     }
  810.  
  811.     for (i = 0; playlist[i].start; i++)
  812.         if (track >= playlist[i].start && track < playlist[i].end)
  813.         {
  814.             cur_listno = i + 1;
  815.             cur_firsttrack = playlist[i].start;
  816.             cur_lasttrack = playlist[i].end - 1;
  817.             return;
  818.         }
  819.     
  820.     /*
  821.      * Couldn't find the track in question.  Make a special entry with
  822.      * just that track.
  823.      */
  824.     if (! playlist[i].start)
  825.     {
  826.         playlist = realloc(playlist, (i + 2) * sizeof(*playlist));
  827.         if (playlist == NULL)
  828.         {
  829.             perror("playlist realloc");
  830.             exit(1);
  831.         }
  832.  
  833.         playlist[i + 1].start = playlist[i + 1].end = 0;
  834.         playlist[i + 1].starttime = playlist[i].starttime +
  835.             cd->trk[track - 1].length;
  836.         playlist[i].start = track;
  837.         playlist[i].end = track + 1;
  838.         cur_listno = i + 1;
  839.         cur_firsttrack = track;
  840.         cur_lasttrack = track;
  841.     }
  842. }
  843.