The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
 /*********************************************
NAME: linux.h
FUNCTION: linux based cddb id generation code
CREATED BY: David Shultz
CREATED ON: 08/03/2001
*********************************************/
#ifndef LINUX_H
#define LINUX_H

struct toc {
    int min, sec, frame;
} cdtoc[100];

struct discdata {
    unsigned long discid;
    int num_of_trks;
    int track_offsets[100];
    int seconds;
};

unsigned int cddb_sum(int n) {
    unsigned int ret;

    ret = 0;
    while (n > 0) {
        ret += (n % 10);
        n /= 10;
    }
    return ret;
}

unsigned long cddb_discid(int tot_trks) {
    unsigned int i, t = 0, n = 0;

    i = 0;
    while (i < tot_trks) {
        n = n + cddb_sum((cdtoc[i].min * 60) + cdtoc[i].sec);
        i++;
    }
    t = ((cdtoc[tot_trks].min * 60) + cdtoc[tot_trks].sec) -
        ((cdtoc[0].min * 60) + cdtoc[0].sec);
    return ((n % 0xff) << 24 | t << 8 | tot_trks);
}

struct discdata get_disc_id(char* dev) {
    struct discdata data;
    int i;

    data.num_of_trks = read_toc(dev);

    if (data.num_of_trks == -1) {
        return data;
    }

    data.discid = cddb_discid(data.num_of_trks);

    for (i = 0; i < data.num_of_trks; i++) {
        data.track_offsets[i] = (cdtoc[i].frame);
    }

    data.seconds = (cdtoc[data.num_of_trks].frame)/75;

    return data;
}

int read_toc(char* dev) {
    int drive;
    struct cdrom_tochdr tochdr;
    struct cdrom_tocentry tocentry;
    int i, status;

    drive = open(dev, O_RDONLY | O_NONBLOCK);
    if (drive == -1) {
      //printf("Device Error: %d\n", errno);
                return(-1);
    }

        status = ioctl(drive, CDROM_DRIVE_STATUS, CDSL_CURRENT);
        if (status<0) {
          //printf("Error: Error getting drive status\n");
                return(-1);
        } else {
                switch(status) {
                        case CDS_DISC_OK:
                                //printf("Disc ok, moving on\n");
                                break;
                        case CDS_TRAY_OPEN:
                                //printf("Error: Drive reporting tray open...exiting\n");
                                close(drive);
                                return(-1);
                        case CDS_DRIVE_NOT_READY:
                                //printf("Error: Drive Not Ready...exiting\n");
                                close(drive);
                                return(-1);
                        default:
                                //printf("This shouldn't happen\n");
                                close(drive);
                                return(-1);
                }
        }



    if (ioctl(drive, CDROMREADTOCHDR, &tochdr) == -1) {
                switch(errno) {
                        case EBADF:
                          //printf("Error: Invalid device...exiting\n");
                                break;
                        case EFAULT:
                          //printf("Error: Memory Write Error...exiting\n");
                                break;
                        case ENOTTY:
                          //printf("Error: Invalid device or Request type...exiting\n");
                                break;
                        case EINVAL:
                          //printf("Error: Invalid REQUEST...exiting\n");
                                break;
                        case EAGAIN:
                          //printf("Error: Drive not ready...exiting\n");
                                break;
                        default:
                          //printf("Error: %d\n", errno);
				break;
		}
    }
    
    for (i = tochdr.cdth_trk0; i <= tochdr.cdth_trk1; i++) {
        tocentry.cdte_track = i;
        tocentry.cdte_format = CDROM_MSF;
        ioctl(drive, CDROMREADTOCENTRY, &tocentry);
        cdtoc[i-1].min = tocentry.cdte_addr.msf.minute;
        cdtoc[i-1].sec = tocentry.cdte_addr.msf.second;
        cdtoc[i-1].frame = tocentry.cdte_addr.msf.frame;
        cdtoc[i-1].frame += cdtoc[i-1].min*60*75;
        cdtoc[i-1].frame += cdtoc[i-1].sec*75;
    }
    tocentry.cdte_track = 0xAA;
    tocentry.cdte_format = CDROM_MSF;
    ioctl(drive, CDROMREADTOCENTRY, &tocentry);
    cdtoc[tochdr.cdth_trk1].min = tocentry.cdte_addr.msf.minute;
    cdtoc[tochdr.cdth_trk1].sec = tocentry.cdte_addr.msf.second;
    cdtoc[tochdr.cdth_trk1].frame = tocentry.cdte_addr.msf.frame;
    cdtoc[tochdr.cdth_trk1].frame += cdtoc[tochdr.cdth_trk1].min*60*75;
    cdtoc[tochdr.cdth_trk1].frame += cdtoc[tochdr.cdth_trk1].sec*75;
    close(drive);
    return tochdr.cdth_trk1;
}

#endif //LINUX_H