diff options
Diffstat (limited to 'wodim/cue.c')
-rw-r--r-- | wodim/cue.c | 1198 |
1 files changed, 1198 insertions, 0 deletions
diff --git a/wodim/cue.c b/wodim/cue.c new file mode 100644 index 0000000..0eb88b3 --- /dev/null +++ b/wodim/cue.c @@ -0,0 +1,1198 @@ +/* + * 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); +} |