Logo Search packages:      
Sourcecode: cdrkit version File versions  Download package

cue.c

/*
 * This file has been modified for the cdrkit suite.
 *
 * The behaviour and appearence of the program code below can differ to a major
 * extent from the version distributed by the original author(s).
 *
 * For details, see Changelog file distributed with the cdrkit package. If you
 * received this file from another source then ask the distributing person for
 * a log of modifications.
 *
 */

/* @(#)cue.c      1.20 04/03/02 Copyright 2001-2004 J. Schilling */
/*
 *    Cue sheet parser
 *
 *    Copyright (c) 2001-2004 J. Schilling
 */
/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; see the file COPYING.  If not, write to the Free Software
 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include <mconfig.h>
#include <stdio.h>
#include <stdxlib.h>
#include <unixstd.h>
#include <standard.h>
#include <fctldefs.h>
#include <statdefs.h>
#include <vadefs.h>
#include <schily.h>
#include <strdefs.h>
#include <utypes.h>
#include <ctype.h>
#include <errno.h>

#include "xio.h"
#include "cdtext.h"
#include "wodim.h"
#include "auheader.h"
#include "libport.h"

typedef struct state {
      char  *filename;
      void  *xfp;
      Llong trackoff;
      Llong filesize;
      int   filetype;
      int   tracktype;
      int   sectype;
      int   dbtype;
      int   secsize;
      int   dataoff;
      int   state;
      int   track;
      int   index;
      long  index0;
      long  index1;           /* Current index 1 value      */
      long  secoff;           /* Old index 1 value          */
      long  pregapsize;
      long  postgapsize;
      int   flags;
} state_t;

static      char  linebuf[4096];
static      char  *fname;
static      char  *linep;
static      char  *wordendp;
static      char  wordendc;
static      int   olinelen;
static      int   linelen;
static      int   lineno;

static      char  worddelim[] = "=:,/";
static      char  nulldelim[] = "";

#define     STATE_NONE  0
#define     STATE_POSTGAP     1
#define     STATE_TRACK 2
#define     STATE_FLAGS 3
#define     STATE_INDEX0      4
#define     STATE_INDEX1      5

typedef struct keyw {
      char  *k_name;
      int   k_type;
} keyw_t;

/*
 *    Keywords (first word on line):
 *          CATALOG           - global    CATALOG           <MCN>
 *          CDTEXTFILE  - global    CDTEXTFILE  <fname>
 *          FILE        - track static    FILE        <fame> <type>
 *          FLAGS       - track static    FLAGS       <flag> ...
 *          INDEX       - track static    INDEX       <#> <mm:ss:ff>
 *          ISRC        - track static    ISRC        <ISRC>
 *          PERFORMER   - global/static   PERFORMER   <string>
 *          POSTGAP           - track locak     POSTGAP           <mm:ss:ff>
 *          PREGAP            - track static    PREGAP            <mm:ss:ff>
 *          REM         - anywhere  REM         <comment>
 *          SONGWRITER  - global/static   SONGWRITER  <string>
 *          TITLE       - global/static   TITLE       <string>
 *          TRACK       - track static    TRACK       <#> <datatype>
 *
 *    Order of keywords:
 *          CATALOG
 *          CDTEXTFILE
 *          PERFORMER | SONGWRITER | TITLE            Doc says past FILE...
 *          FILE                          Must be past CATALOG
 *          ------- Repeat the following:       mehrere FILE Commands?
 *          TRACK
 *          FLAGS | ISRC | PERFORMER | PREGAP | SONGWRITER | TITLE
 *          INDEX
 *          POSTGAP
 */

#define     K_G         0x10000           /* Global               */
#define     K_T         0x20000           /* Track static               */
#define     K_A         (K_T | K_G) /* Global & Track static            */

#define     K_MCN       (0 | K_G)   /* Media catalog number       */
#define     K_TEXTFILE  (1 | K_G)   /* CD-Text binary file        */
#define     K_FILE            (2 | K_T)   /* Input data file            */
#define     K_FLAGS           (3 | K_T)   /* Flags for ctrl nibble      */
#define     K_INDEX           (4 | K_T)   /* Index marker for track     */
#define     K_ISRC            (5 | K_T)   /* ISRC string for track      */
#define     K_PERFORMER (6 | K_A)   /* CD-Text Performer          */
#define     K_POSTGAP   (7 | K_T)   /* Post gap for track (autogen)     */
#define     K_PREGAP    (8 | K_T)   /* Pre gap for track (autogen)      */
#define     K_REM       (9 | K_A)   /* Remark (Comment)           */
#define     K_SONGWRITER      (10| K_A)   /* CD-Text Songwriter         */
#define     K_TITLE           (11| K_A)   /* CD-Text Title        */
#define     K_TRACK           (12| K_T)   /* Track marker               */


static keyw_t     keywords[] = {
      { "CATALOG",      K_MCN },
      { "CDTEXTFILE",   K_TEXTFILE },
      { "FILE",   K_FILE },
      { "FLAGS",  K_FLAGS },
      { "INDEX",  K_INDEX },
      { "ISRC",   K_ISRC },
      { "PERFORMER",    K_PERFORMER },
      { "POSTGAP",      K_POSTGAP },
      { "PREGAP", K_PREGAP },
      { "REM",    K_REM },
      { "SONGWRITER",   K_SONGWRITER },
      { "TITLE",  K_TITLE },
      { "TRACK",  K_TRACK },
      { NULL,           0 },
};


/*
 *    Filetypes - argument to FILE Keyword (one only):
 *
 *          BINARY            - Intel binary file (least significant byte first)
 *          MOTOTOLA    - Motorola binary file (most significant byte first)
 *          AIFF        - Audio AIFF file
 *          AU          - Sun Audio file
 *          WAVE        - Audio WAVE file
 *          MP3         - Audio MP3 file
 */
#define     K_BINARY    100
#define     K_MOTOROLA  101
#define     K_AIFF            102
#define     K_AU        103
#define     K_WAVE            104
#define     K_MP3       105
#define     K_OGG       106

static keyw_t     filetypes[] = {
      { "BINARY", K_BINARY },
      { "MOTOROLA",     K_MOTOROLA },
      { "AIFF",   K_AIFF },
      { "AU",           K_AU },
      { "WAVE",   K_WAVE },
      { "MP3",    K_MP3 },
      { "OGG",    K_OGG },
      { NULL,           0 },
};

/*
 *    Flags - argument to FLAGS Keyword (more than one allowed):
 *          DCP         - Digital copy permitted
 *          4CH         - Four channel audio
 *          PRE         - Pre-emphasis enabled (audio tracks only)
 *          SCMS        - Serial copy management system (not supported by all recorders)
 */
#define     K_DCP       1000
#define     K_4CH       1001
#define     K_PRE       1002
#define     K_SCMS            1003

static keyw_t     flags[] = {
      { "DCP",    K_DCP },
      { "4CH",    K_4CH },
      { "PRE",    K_PRE },
      { "SCMS",   K_SCMS },
      { NULL,           0 },
};

/*
 *    Datatypes - argument to TRACK Keyword (one only):
 *          AUDIO       - Audio/Music (2352)
 *          CDG         - Karaoke CD+G (2448)
 *          MODE1/2048  - CDROM Mode1 Data (cooked)
 *          MODE1/2352  - CDROM Mode1 Data (raw)
 *          MODE2/2336  - CDROM-XA Mode2 Data
 *          MODE2/2352  - CDROM-XA Mode2 Data
 *          CDI/2336    - CDI Mode2 Data
 *          CDI/2352    - CDI Mode2 Data
 */
#define     K_AUDIO           10000
#define     K_CDG       10001
#define     K_MODE1           10002
#define     K_MODE2           10003
#define     K_CDI       10004

static keyw_t     dtypes[] = {
      { "AUDIO",  K_AUDIO },
      { "CDG",    K_CDG },
      { "MODE1",  K_MODE1 },
      { "MODE2",  K_MODE2 },
      { "CDI",    K_CDI },
      { NULL,           0 },
};


int   parsecue(char *cuefname, track_t trackp[]);
void  fparsecue(FILE *f, track_t trackp[]);
static      void  parse_mcn(track_t trackp[], state_t *sp);
static      void  parse_textfile(track_t trackp[], state_t *sp);
static      void  parse_file(track_t trackp[], state_t *sp);
static      void  parse_flags(track_t trackp[], state_t *sp);
static      void  parse_index(track_t trackp[], state_t *sp);
static      void  parse_isrc(track_t trackp[], state_t *sp);
static      void  parse_performer(track_t trackp[], state_t *sp);
static      void  parse_postgap(track_t trackp[], state_t *sp);
static      void  parse_pregap(track_t trackp[], state_t *sp);
static      void  parse_songwriter(track_t trackp[], state_t *sp);
static      void  parse_title(track_t trackp[], state_t *sp);
static      void  parse_track(track_t trackp[], state_t *sp);
static      void  parse_offset(long *lp);
static      void  newtrack(track_t trackp[], state_t *sp);

static      keyw_t      *lookup(char *word, keyw_t table[]);
static      void  wdebug(void);
static      FILE  *cueopen(char *name);
static      char  *cuename(void);
static      char  *nextline(FILE *f);
static      void  ungetline(void);
static      char  *skipwhite(const char *s);
static      char  *peekword(void);
static      char  *lineend(void);
static      char  *markword(char *delim);
static      char  *getnextitem(char *delim);
static      char  *neednextitem(char *delim);
static      char  *nextword(void);
static      char  *needword(void);
static      char  *curword(void);
static      char  *nextitem(void);
static      char  *needitem(void);
static      void  checkextra(void);
static      void  cueabort(const char *fmt, ...);

#ifdef      CUE_MAIN
int   debug;
int   xdebug = 1;

int write_secs(void);
int write_secs() { return (-1); }

int 
main(int argc, char *argv[])
{
      int   i;
      track_t     track[MAX_TRACK+2];     /* Max tracks + track 0 + track AA */

      save_args(argc, argv);

      fillbytes(track, sizeof (track), '\0');
      for (i = 0; i < MAX_TRACK+2; i++)
            track[i].track = track[i].trackno = i;
      track[0].tracktype = TOC_MASK;


      parsecue(argv[1], track);
      return (0);
}
#else
extern      int   xdebug;
#endif

int 
parsecue(char *cuefname, track_t trackp[])
{
      FILE  *f = cueopen(cuefname);

      fparsecue(f, trackp);
      return (0);
}

void 
fparsecue(FILE *f, track_t trackp[])
{
      char  *word;
      struct keyw *kp;
      BOOL  isglobal = TRUE;
      state_t     state;

      state.filename    = NULL;
      state.xfp   = NULL;
      state.trackoff    = 0;
      state.filesize    = 0;
      state.filetype    = 0;
      state.tracktype   = 0;
      state.sectype     = 0;
      state.dbtype      = 0;
      state.secsize     = 0;
      state.dataoff     = 0;
      state.state = STATE_NONE;
      state.track = 0;
      state.index = -1;
      state.index0      = -1;
      state.index1      = -1;
      state.secoff      = 0;
      state.pregapsize = -1;
      state.postgapsize = -1;
      state.flags = 0;

      if (xdebug > 1)
            printf("---> Entering CUE Parser...\n");
      do {
            if (nextline(f) == NULL) {
                  /*
                   * EOF on CUE File
                   * Do post processing here
                   */
                  if (state.state < STATE_INDEX1)
                        cueabort("Incomplete CUE file");
                  if (state.xfp)
                        xclose(state.xfp);
                  if (xdebug > 1) {
                        printf("---> CUE Parser got EOF, found %d tracks.\n",
                                                state.track);
                  }
                  return;
            }
            word = nextitem();
            if (*word == '\0')      /* empty line */
                  continue;

            if (xdebug > 1)
                  printf("\nKEY: '%s'     %s\n", word, peekword());
            kp = lookup(word, keywords);
            if (kp == NULL)
                  cueabort("Unknown CUE keyword '%s'", word);

            if ((kp->k_type & K_G) == 0) {
                  if (isglobal)
                        isglobal = FALSE;
            }
            if ((kp->k_type & K_T) == 0) {
                  if (!isglobal)
                        cueabort("Badly placed CUE keyword '%s'", word);
            }
/*          printf("%s-", isglobal ? "G" : "T");*/
/*          wdebug();*/

            switch (kp->k_type) {

            case K_MCN:    parse_mcn(trackp, &state);       break;
            case K_TEXTFILE:   parse_textfile(trackp, &state);    break;
            case K_FILE:         parse_file(trackp, &state);            break;
            case K_FLAGS:        parse_flags(trackp, &state);           break;
            case K_INDEX:        parse_index(trackp, &state);           break;
            case K_ISRC:         parse_isrc(trackp, &state);            break;
            case K_PERFORMER:  parse_performer(trackp, &state);   break;
            case K_POSTGAP:      parse_postgap(trackp, &state);   break;
            case K_PREGAP:       parse_pregap(trackp, &state);    break;
            case K_REM:                               break;
            case K_SONGWRITER: parse_songwriter(trackp, &state);  break;
            case K_TITLE:        parse_title(trackp, &state);           break;
            case K_TRACK:        parse_track(trackp, &state);           break;

            default:
                  cueabort("Panic: unknown CUE command '%s'", word);
            }
      } while (1);
}

static void 
parse_mcn(track_t trackp[], state_t *sp)
{
      char  *word;
      textptr_t *txp;

      if (sp->track != 0)
            cueabort("CATALOG keyword must be before first TRACK");

      word = needitem();
      setmcn(word, &trackp[0]);
      txp = gettextptr(0, trackp); /* MCN is isrc for trk 0 */
      txp->tc_isrc = strdup(word);

      checkextra();
}

static void 
parse_textfile(track_t trackp[], state_t *sp)
{
      char  *word;

      if (sp->track != 0)
            cueabort("CDTEXTFILE keyword must be before first TRACK");

      word = needitem();

      if (trackp[MAX_TRACK+1].flags & TI_TEXT) {
            if (!checktextfile(word)) {
                  comerrno(EX_BAD,
                        "Cannot use '%s' as CD-Text file.\n",
                        word);
            }
            trackp[0].flags |= TI_TEXT;
      } else {
            errmsgno(EX_BAD, "Ignoring CDTEXTFILE '%s'.\n", word);
            errmsgno(EX_BAD, "If you like to write CD-Text, call wodim -text.\n");
      }

      checkextra();
}

static void 
parse_file(track_t trackp[], state_t *sp)
{
      char  cname[1024];
      char  newname[1024];
      struct keyw *kp;
      char  *word;
      char  *filetype;
      struct stat st;
#ifdef      hint
      Llong       lsize;
#endif

      if (sp->filename != NULL)
            cueabort("Only one FILE allowed");

      word = needitem();
      if (sp->xfp)
            xclose(sp->xfp);
      sp->xfp = xopen(word, O_RDONLY|O_BINARY, 0);
      if (sp->xfp == NULL && geterrno() == ENOENT) {
            char  *p;

            if (strchr(word, '/') == 0 &&
                strchr(cuename(), '/') != 0) {
                  snprintf(cname, sizeof (cname),
                        "%s", cuename());
                  p = strrchr(cname, '/');
                  if (p)
                        *p = '\0';
                  snprintf(newname, sizeof (newname),
                        "%s/%s", cname, word);
                  word = newname;
                  sp->xfp = xopen(word, O_RDONLY|O_BINARY, 0);
            }
      }
      if (sp->xfp == NULL)
            comerr("Cannot open FILE '%s'.\n", word);

      sp->filename       = strdup(word);
      sp->trackoff       = 0;
      sp->filesize       = 0;
      sp->flags   &= ~TI_SWAB;      /* Reset what we might set for FILE */

      filetype = needitem();
      kp = lookup(filetype, filetypes);
      if (kp == NULL)
            cueabort("Unknown filetype '%s'", filetype);

      switch (kp->k_type) {

      case K_BINARY:
      case K_MOTOROLA:
                  if (fstat(xfileno(sp->xfp), &st) >= 0 &&
                      S_ISREG(st.st_mode)) {
                        sp->filesize = st.st_size;
                  } else {
                        cueabort("Unknown file size for FILE '%s'",
                                                sp->filename);
                  }
                  break;
      case K_AIFF:
                  cueabort("Unsupported filetype '%s'", kp->k_name);
                  break;
      case K_AU:
                  sp->filesize = ausize(xfileno(sp->xfp));
                  break;
      case K_WAVE:
                  sp->filesize = wavsize(xfileno(sp->xfp));
                  sp->flags |= TI_SWAB;
                  break;
      case K_MP3:
      case K_OGG:
                  cueabort("Unsupported filetype '%s'", kp->k_name);
                  break;

      default:    cueabort("Panic: unknown filetype '%s'", filetype);
      }

      if (sp->filesize == AU_BAD_CODING) {
            cueabort("Inappropriate audio coding in '%s'",
                                          sp->filename);
      }
      if (xdebug > 0)
            printf("Track %d File '%s' Filesize %lld\n",
                  sp->track, sp->filename, sp->filesize);

      sp->filetype = kp->k_type;

      checkextra();


#ifdef      hint
            trackp->itracksize = lsize;
            if (trackp->itracksize != lsize)
                  comerrno(EX_BAD, "This OS cannot handle large audio images.\n");
#endif
}

static void 
parse_flags(track_t trackp[], state_t *sp)
{
      struct keyw *kp;
      char  *word;

      if ((sp->state < STATE_TRACK) ||
          (sp->state >= STATE_INDEX0))
            cueabort("Badly placed FLAGS keyword");
      sp->state = STATE_FLAGS;

      do {
            word = needitem();
            kp = lookup(word, flags);
            if (kp == NULL)
                  cueabort("Unknown flag '%s'", word);

            switch (kp->k_type) {

            case K_DCP: sp->flags |= TI_COPY;   break;
            case K_4CH: sp->flags |= TI_QUADRO; break;
            case K_PRE: sp->flags |= TI_PREEMP; break;
            case K_SCMS:      sp->flags |= TI_SCMS;   break;
            default:    cueabort("Panic: unknown FLAG '%s'", word);
            }

      } while (peekword() < lineend());

      if (xdebug > 0)
            printf("Track %d flags 0x%08X\n", sp->track, sp->flags);
}

static void 
parse_index(track_t trackp[], state_t *sp)
{
      char  *word;
      long  l;
      int   track = sp->track;

      if (sp->state < STATE_TRACK)
            cueabort("Badly placed INDEX keyword");


      word = needitem();
      if (*astolb(word, &l, 10) != '\0')
            cueabort("Not a number '%s'", word);
      if (l < 0 || l > 99)
            cueabort("Illegal index '%s'", word);

      if ((sp->index < l) &&
          (((sp->index + 1) == l) || l == 1))
            sp->index = l;
      else
            cueabort("Badly placed INDEX %ld number", l);

      if (l > 0)
            sp->state = STATE_INDEX1;
      else
            sp->state = STATE_INDEX0;

      parse_offset(&l);

      if (xdebug > 1)
            printf("Track %d Index %d %ld\n", sp->track, sp->index, l);

      if (sp->index == 0)
            sp->index0 = l;
      if (sp->index == 1) {
            sp->index1 = l;
            trackp[track].nindex = 1;
            newtrack(trackp, sp);

            if (xdebug > 1) {
                  printf("Track %d pregapsize %ld\n",
                        sp->track, trackp[track].pregapsize);
            }
      }
      if (sp->index == 2) {
            trackp[track].tindex = malloc(100*sizeof (long));
            trackp[track].tindex[1] = 0;
            trackp[track].tindex[2] = l - sp->index1;
            trackp[track].nindex = 2;
      }
      if (sp->index > 2) {
            trackp[track].tindex[sp->index] = l - sp->index1;
            trackp[track].nindex = sp->index;
      }

      checkextra();
}

static void 
parse_isrc(track_t trackp[], state_t *sp)
{
      char  *word;
      textptr_t *txp;
      int   track = sp->track;

      if (track == 0)
            cueabort("ISRC keyword must be past first TRACK");

      if ((sp->state < STATE_TRACK) ||
          (sp->state >= STATE_INDEX0))
            cueabort("Badly placed ISRC keyword");
      sp->state = STATE_FLAGS;

      word = needitem();
      setisrc(word, &trackp[track]);
      txp = gettextptr(track, trackp);
      txp->tc_isrc = strdup(word);

      checkextra();
}

static void 
parse_performer(track_t trackp[], state_t *sp)
{
      char  *word;
      textptr_t *txp;

      word = needitem();
      txp = gettextptr(sp->track, trackp);
      txp->tc_performer = strdup(word);

      checkextra();
}

static void 
parse_postgap(track_t trackp[], state_t *sp)
{
      long  l;

      if (sp->state < STATE_INDEX1)
            cueabort("Badly placed POSTGAP keyword");
      sp->state = STATE_POSTGAP;

      parse_offset(&l);
      sp->postgapsize = l;

      checkextra();
}

static void 
parse_pregap(track_t trackp[], state_t *sp)
{
      long  l;

      if ((sp->state < STATE_TRACK) ||
          (sp->state >= STATE_INDEX0))
            cueabort("Badly placed PREGAP keyword");
      sp->state = STATE_FLAGS;

      parse_offset(&l);
      sp->pregapsize = l;

      checkextra();
}

static void 
parse_songwriter(track_t trackp[], state_t *sp)
{
      char  *word;
      textptr_t *txp;

      word = needitem();
      txp = gettextptr(sp->track, trackp);
      txp->tc_songwriter = strdup(word);

      checkextra();
}

static void 
parse_title(track_t trackp[], state_t *sp)
{
      char  *word;
      textptr_t *txp;

      word = needitem();
      txp = gettextptr(sp->track, trackp);
      txp->tc_title = strdup(word);

      checkextra();
}

static void 
parse_track(track_t trackp[], state_t *sp)
{
      struct keyw *kp;
      char  *word;
      long  l;
      long  secsize = -1;

      if ((sp->state >= STATE_TRACK) &&
          (sp->state < STATE_INDEX1))
            cueabort("Badly placed TRACK keyword");
      sp->state = STATE_TRACK;
      sp->index = -1;

      word = needitem();
      if (*astolb(word, &l, 10) != '\0')
            cueabort("Not a number '%s'", word);
      if (l <= 0 || l > 99)
            cueabort("Illegal TRACK number '%s'", word);

      if ((sp->track < l) &&
          (((sp->track + 1) == l) || sp->track == 0))
            sp->track = l;
      else
            cueabort("Badly placed TRACK %ld number", l);

      word = needword();
      kp = lookup(word, dtypes);
      if (kp == NULL)
            cueabort("Unknown filetype '%s'", word);

      if (wordendc == '/') {
            word = needitem();
            if (*astol(++word, &secsize) != '\0')
                  cueabort("Not a number '%s'", word);
      }

      /*
       * Reset all flags that may be set in TRACK & FLAGS lines
       */
      sp->flags &= ~(TI_AUDIO|TI_COPY|TI_QUADRO|TI_PREEMP|TI_SCMS);

      if (kp->k_type == K_AUDIO)
            sp->flags |= TI_AUDIO;

      switch (kp->k_type) {

      case K_CDG:
            if (secsize < 0)
                  secsize = 2448;
      case K_AUDIO:
            if (secsize < 0)
                  secsize = 2352;

            sp->tracktype = TOC_DA;
            sp->sectype = SECT_AUDIO;
            sp->dbtype = DB_RAW;
            sp->secsize = secsize;
            sp->dataoff = 0;
            if (secsize != 2352)
                  cueabort("Unsupported sector size %ld for audio", secsize);
            break;

      case K_MODE1:
            if (secsize < 0)
                  secsize = 2048;

            sp->tracktype = TOC_ROM;
            sp->sectype = SECT_ROM;
            sp->dbtype = DB_ROM_MODE1;
            sp->secsize = secsize;
            sp->dataoff = 16;
            /*
             * XXX Sector Size == 2352 ???
             * XXX It seems that there exist bin/cue pairs with this value
             */
            if (secsize != 2048)
                  cueabort("Unsupported sector size %ld for data", secsize);
            break;

      case K_MODE2:
      case K_CDI:
            sp->tracktype = TOC_ROM;
            sp->sectype = SECT_MODE_2;
            sp->dbtype = DB_ROM_MODE2;
            sp->secsize = secsize;
            sp->dataoff = 16;
            if (secsize == 2352) {
                  sp->tracktype = TOC_XA2;
                  sp->sectype = SECT_MODE_2_MIX;
                  sp->sectype |= ST_MODE_RAW;
                  sp->dbtype = DB_RAW;
                  sp->dataoff = 0;
            } else if (secsize != 2336)
                  cueabort("Unsupported sector size %ld for mode2", secsize);
            if (kp->k_type == K_CDI)
                  sp->tracktype = TOC_CDI;
            break;

      default:    cueabort("Panic: unknown datatype '%s'", word);
      }

      if (sp->flags & TI_PREEMP)
            sp->sectype |= ST_PREEMPMASK;
      sp->secsize = secsize;

      if (xdebug > 1) {
            printf("Track %d Tracktype %s/%d\n",
                  sp->track, kp->k_name, sp->secsize);
      }

      checkextra();
}

static void 
parse_offset(long *lp)
{
      char  *word;
      char  *p;
      long  m = -1;
      long  s = -1;
      long  f = -1;

      word = needitem();

      if (strchr(word, ':') == NULL) {
            if (*astol(word, lp) != '\0')
                  cueabort("Not a number '%s'", word);
            return;
      }
      if (*(p = astolb(word, &m, 10)) != ':')
            cueabort("Not a number '%s'", word);
      if (m < 0 || m >= 160)
            cueabort("Illegal minute value in '%s'", word);
      p++;
      if (*(p = astolb(p, &s, 10)) != ':')
            cueabort("Not a number '%s'", p);
      if (s < 0 || s >= 60)
            cueabort("Illegal second value in '%s'", word);
      p++;
      if (*(p = astolb(p, &f, 10)) != '\0')
            cueabort("Not a number '%s'", p);
      if (f < 0 || f >= 75)
            cueabort("Illegal frame value in '%s'", word);

      m = m * 60 + s;
      m = m * 75 + f;
      *lp = m;
}

/*--------------------------------------------------------------------------*/
static void 
newtrack(track_t trackp[], state_t *sp)
{
      register int      i;
      register int      track = sp->track;
            Llong tracksize;

      if (xdebug > 1)
            printf("-->Newtrack %d\n", track);
      if (track > 1) {
            tracksize = (sp->index1 - sp->secoff) * trackp[track-1].secsize;

            if (xdebug > 1)
                  printf("    trackoff %lld filesize %lld index1 %ld size %ld/%lld\n",
                        sp->trackoff, sp->filesize, sp->index1,
                        sp->index1 - sp->secoff,
                        tracksize);

            trackp[track-1].itracksize = tracksize;
            trackp[track-1].tracksize = tracksize;
            trackp[track-1].tracksecs = sp->index1 - sp->secoff;

            sp->trackoff += tracksize;
            sp->secoff = sp->index1;
      }
      /*
       * Make 'tracks' immediately usable in track structure.
       */
      for (i = 0; i < MAX_TRACK+2; i++)
            trackp[i].tracks = track;

      trackp[track].filename = sp->filename;
      trackp[track].xfp = xopen(sp->filename, O_RDONLY|O_BINARY, 0);
      trackp[track].trackstart = 0L;
/*
SEtzen wenn tracksecs bekannt sind
d.h. mit Index0 oder Index 1 vom nächsten track

      trackp[track].itracksize = tracksize;
      trackp[track].tracksize = tracksize;
      trackp[track].tracksecs = -1L;
*/
      tracksize = sp->filesize - sp->trackoff;

      trackp[track].itracksize = tracksize;
      trackp[track].tracksize = tracksize;
      trackp[track].tracksecs = (tracksize + sp->secsize - 1) / sp->secsize;

      if (xdebug > 1)
            printf("    Remaining Filesize %lld (%lld secs)\n",
                  (sp->filesize-sp->trackoff),
                  (sp->filesize-sp->trackoff +sp->secsize - 1) / sp->secsize);

      if (sp->pregapsize >= 0) {
/*          trackp[track].flags &= ~TI_PREGAP;*/
            sp->flags &= ~TI_PREGAP;
            trackp[track].pregapsize = sp->pregapsize;
      } else {
/*          trackp[track].flags |= TI_PREGAP;*/
            if (track > 1)
                  sp->flags |= TI_PREGAP;
            if (track == 1)
                  trackp[track].pregapsize = sp->index1 + 150;
            else if (sp->index0 < 0)
                  trackp[track].pregapsize = -1;
            else
                  trackp[track].pregapsize = sp->index1 - sp->index0;
      }
/*    trackp[track].padsecs = xxx*/

      trackp[track].isecsize = sp->secsize;
      trackp[track].secsize = sp->secsize;
      trackp[track].flags = sp->flags | trackp[0].flags;

      trackp[track].secspt = 0;     /* transfer size is set up in set_trsizes() */
/*    trackp[track].pktsize = pktsize; */
      trackp[track].pktsize = 0;
      trackp[track].trackno = sp->track;
      trackp[track].sectype = sp->sectype;

      trackp[track].dataoff = sp->dataoff;
      trackp[track].tracktype = sp->tracktype;
      trackp[track].dbtype = sp->dbtype;

      if (track == 1) {
            trackp[0].tracktype &= ~TOC_MASK;
            trackp[0].tracktype |= sp->tracktype;

            if (xdebug > 1) {
                  printf("Track %d Tracktype %X\n",
                              0, trackp[0].tracktype);
            }
      }
      if (xdebug > 1) {
            printf("Track %d Tracktype %X\n",
                        track, trackp[track].tracktype);
      }
      trackp[track].nindex = 1;
      trackp[track].tindex = 0;

      if (xdebug > 1) {
            printf("Track %d flags 0x%08X\n", 0, trackp[0].flags);
            printf("Track %d flags 0x%08X\n", track, trackp[track].flags);
      }
}

/*--------------------------------------------------------------------------*/
static keyw_t *
lookup(char *word, keyw_t table[])
{
      register keyw_t   *kp = table;

      while (kp->k_name) {
            if (streql(kp->k_name, word))
                  return (kp);
            kp++;
      }
      return (NULL);
}

/*--------------------------------------------------------------------------*/
/*
 * Parser low level functions start here...
 */

static void 
wdebug()
{
/*          printf("WORD: '%s' rest '%s'\n", word, peekword());*/
            printf("WORD: '%s' rest '%s'\n", linep, peekword());
            printf("linep %lX peekword %lX end %lX\n",
                  (long)linep, (long)peekword(), (long)&linebuf[linelen]);
}

static FILE *
cueopen(char *name)
{
      FILE  *f;

      f = fileopen(name, "r");
      if (f == NULL)
            comerr("Cannot open '%s'.\n", name);

      fname = name;
      return (f);
}

static char *
cuename()
{
      return (fname);
}

static char *
nextline(FILE *f)
{
      register int      len;

      do {
            fillbytes(linebuf, sizeof (linebuf), '\0');
            len = rols_fgetline(f, linebuf, sizeof (linebuf));
            if (len < 0)
                  return (NULL);
            if (len > 0 && linebuf[len-1] == '\r') {
                  linebuf[len-1] = '\0';
                  len--;
            }
            linelen = len;
            lineno++;
      } while (linebuf[0] == '#');

      olinelen = linelen;
      linep = linebuf;
      wordendp = linep;
      wordendc = *linep;

      return (linep);
}

static void 
ungetline()
{
      linelen = olinelen;
      linep = linebuf;
      *wordendp = wordendc;
      wordendp = linep;
      wordendc = *linep;
}

static char *
skipwhite(const char *s)
{
      register const Uchar    *p = (const Uchar *)s;

      while (*p) {
            if (!isspace(*p))
                  break;
            p++;
      }
      return ((char *)p);
}

static char *
peekword()
{
      return (&wordendp[1]);
}

static char *
lineend()
{
      return (&linebuf[linelen]);
}

static char *
markword(char *delim)
{
      register    BOOL  quoted = FALSE;
      register    Uchar c;
      register    Uchar *s;
      register    Uchar *from;
      register    Uchar *to;

      for (s = (Uchar *)linep; (c = *s) != '\0'; s++) {
            if (c == '"') {
                  quoted = !quoted;
/*                strcpy((char *)s, (char *)&s[1]);*/
                  for (to = s, from = &s[1]; *from; ) {
                        c = *from++;
                        if (c == '\\' && quoted && (*from == '\\' || *from == '"'))
                              c = *from++;
                        *to++ = c;
                  }
                  *to = '\0';
                  c = *s;
linelen--;
            }
            if (!quoted && isspace(c))
                  break;
            if (!quoted && strchr(delim, c) && s > (Uchar *)linep)
                  break;
      }
      wordendp = (char *)s;
      wordendc = (char)*s;
      *s = '\0';

      return (linep);
}

static char *
getnextitem(char *delim)
{
      *wordendp = wordendc;

      linep = skipwhite(wordendp);
      return (markword(delim));
}

static char *
neednextitem(char *delim)
{
      char  *olinep = linep;
      char  *nlinep;

      nlinep = getnextitem(delim);

      if ((olinep == nlinep) || (*nlinep == '\0'))
            cueabort("Missing text");

      return (nlinep);
}

static char *
nextword()
{
      return (getnextitem(worddelim));
}

static char *
needword()
{
      return (neednextitem(worddelim));
}

static char *
curword()
{
      return (linep);
}

static char *
nextitem()
{
      return (getnextitem(nulldelim));
}

static char *
needitem()
{
      return (neednextitem(nulldelim));
}

static void 
checkextra()
{
      if (peekword() < lineend())
            cueabort("Extra text '%s'", peekword());
}

/* VARARGS1 */
static void cueabort(const char *fmt, ...)
{
      va_list     args;
  va_start(args, fmt);
  vfprintf(stderr, fmt, args);
      va_end(args);
  fprintf(stderr, " on line %d in '%s'.\n", lineno, fname);
  exit(EXIT_FAILURE);
}

Generated by  Doxygen 1.6.0   Back to index