1 /* @(#)cue.c 1.58 19/01/08 Copyright 2001-2019 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)cue.c 1.58 19/01/08 Copyright 2001-2019 J. Schilling";
6 #endif
7 /*
8 * Cue sheet parser
9 *
10 * Copyright (c) 2001-2019 J. Schilling
11 */
12 /*
13 * The contents of this file are subject to the terms of the
14 * Common Development and Distribution License, Version 1.0 only
15 * (the "License"). You may not use this file except in compliance
16 * with the License.
17 *
18 * See the file CDDL.Schily.txt in this distribution for details.
19 * A copy of the CDDL is also available via the Internet at
20 * http://www.opensource.org/licenses/cddl1.txt
21 *
22 * When distributing Covered Code, include this CDDL HEADER in each
23 * file and include the License file CDDL.Schily.txt from this distribution.
24 */
25
26 #include <schily/mconfig.h>
27 #include <schily/stdio.h>
28 #include <schily/stdlib.h>
29 #include <schily/unistd.h>
30 #include <schily/standard.h>
31 #include <schily/fcntl.h>
32 #include <schily/stat.h>
33 #include <schily/varargs.h>
34 #include <schily/schily.h>
35 #include <schily/nlsdefs.h>
36 #include <schily/string.h>
37 #include <schily/utypes.h>
38 #include <schily/ctype.h>
39 #include <schily/errno.h>
40
41 #include "xio.h"
42 #include "cdtext.h"
43 #include "cdrecord.h"
44 #include "auheader.h"
45 #include "schily/libport.h"
46
47 /*#define PARSE_DEBUG*/
48
49 typedef struct state {
50 char *filename; /* Name of file to open */
51 void *xfp; /* Open file */
52 Llong trackoff; /* Current offset in open file */
53 Llong filesize; /* Size of current open file */
54 int filetype; /* File type (e.g. K_WAVE) */
55 int tracktype; /* Track type (e.g. TOC_DA) */
56 int sectype; /* Sector type (e.g. SECT_AUDIO)*/
57 int dbtype; /* Data block type (e.g. DB_RAW)*/
58 int secsize; /* Sector size from TRACK type */
59 int dataoff; /* Data offset from Track type */
60 int state; /* Current state of the parser */
61 int prevstate; /* Previous state of the parser */
62 int track; /* Relative Track index */
63 int trackno; /* Absolute Track number on disk*/
64 int index; /* Last INDEX xx number parsed */
65 long index0; /* Current INDEX 00 if found */
66 long index1; /* Current INDEX 01 if found */
67 long secoff; /* Last INDEX 01 value in file */
68 long pregapsize; /* Pregap size from PREGAP */
69 long postgapsize; /* Postgap size from POSTGAP */
70 int flags; /* Track flags (e.g. TI_COPY) */
71 int pflags; /* Parser flags */
72 } state_t;
73
74 /*
75 * Values for "state" and "prevstate".
76 */
77 #define STATE_NONE 0 /* Initial state of parser */
78 #define STATE_POSTGAP 1 /* Past INDEX before FILE/TRACK */
79 #define STATE_FILE 2 /* FILE keyword found */
80 #define STATE_TRACK 3 /* TRACK keyword found */
81 #define STATE_FLAGS 4 /* FLAGS past TRACK before INDEX*/
82 #define STATE_INDEX0 5 /* INDEX 00 found */
83 #define STATE_INDEX1 6 /* INDEX 01 found */
84 #define STATE_MAX 6 /* # of entries in states[] */
85
86 /*
87 * Flag bits used in "pflags".
88 */
89 #define PF_CDRTOOLS_EXT 0x01 /* Cdrtools extensions allowed */
90 #define PF_INDEX0_PREV 0x02 /* INDEX 00 belongs to prev FILE*/
91 #define PF_FILE_FOUND 0x04 /* FILE command found for TRACK */
92
93 LOCAL char *states[] = {
94 "NONE",
95 "POSTGAP",
96 "FILE",
97 "TRACK",
98 "FLAGS",
99 "INDEX 00",
100 "INDEX 01"
101 };
102
103 typedef struct keyw {
104 char *k_name;
105 int k_type;
106 } keyw_t;
107
108 /*
109 * Keywords (first word on line):
110 * CATALOG - global CATALOG <MCN>
111 * CDTEXTFILE - global CDTEXTFILE <fname>
112 * FILE - track local FILE <fame> <type>
113 * FLAGS - track local FLAGS <flag> ...
114 * INDEX - track local INDEX <#> <mm:ss:ff>
115 * ISRC - track local ISRC <ISRC>
116 * PERFORMER - global/local PERFORMER <string>
117 * POSTGAP - track locak POSTGAP <mm:ss:ff>
118 * PREGAP - track local PREGAP <mm:ss:ff>
119 * REM - anywhere REM <comment>
120 * SONGWRITER - global/local SONGWRITER <string>
121 * TITLE - global/local TITLE <string>
122 * TRACK - track local TRACK <#> <datatype>
123 *
124 * Order of keywords:
125 * CATALOG
126 * CDTEXTFILE
127 * PERFORMER | SONGWRITER | TITLE Doc says past FILE...
128 * FILE Must be past CATALOG
129 * ------- Repeat the following: mehrere FILE Commands?
130 * TRACK
131 * FLAGS | ISRC | PERFORMER | PREGAP | SONGWRITER | TITLE
132 * INDEX
133 * POSTGAP
134 *
135 * Additional keyword rules:
136 * CATALOG once
137 * CDTEXTFILE once
138 * FILE before "other command"
139 * FLAGS one per TRACK, after TRACK before INDEX
140 * INDEX >= 0, <= 99, first 0 or 1, sequential,
141 * first index of a FILE at 00:00:00
142 * ISRC after TRACK before INDEX
143 * PERFORMER
144 * POSTGAP one per TRACK, after all INDEX for current TRACK
145 * PREGAP one per TRACK, after TRACK before INDEX
146 * REM
147 * SONGWRITER
148 * TITLE
149 * TRACK >= 1, <= 99, sequential, >= 1 TRACK per FILE
150 */
151
152 #define K_G 0x10000 /* Global */
153 #define K_T 0x20000 /* Track local */
154 #define K_A (K_T | K_G) /* Global & Track local */
155
156 #define K_ARRANGER (0 | K_A) /* CD-Text Arranger */
157 #define K_MCN (1 | K_G) /* Media catalog number */
158 #define K_TEXTFILE (2 | K_G) /* CD-Text binary file */
159 #define K_COMPOSER (3 | K_A) /* CD-Text Composer */
160 #define K_FILE (4 | K_T) /* Input data file */
161 #define K_FLAGS (5 | K_T) /* Flags for ctrl nibble */
162 #define K_INDEX (6 | K_T) /* Index marker for track */
163 #define K_ISRC (7 | K_T) /* ISRC string for track */
164 #define K_MESSAGE (8 | K_A) /* CD-Text Message */
165 #define K_PERFORMER (9 | K_A) /* CD-Text Performer */
166 #define K_POSTGAP (10 | K_T) /* Post gap for track (autogen) */
167 #define K_PREGAP (11 | K_T) /* Pre gap for track (autogen) */
168 #define K_REM (12 | K_A) /* Remark (Comment) */
169 #define K_SONGWRITER (13| K_A) /* CD-Text Songwriter */
170 #define K_TITLE (14| K_A) /* CD-Text Title */
171 #define K_TRACK (15| K_T) /* Track marker */
172
173
174 LOCAL keyw_t keywords[] = {
175 { "ARRANGER", K_ARRANGER }, /* Not supported by CDR-WIN */
176 { "CATALOG", K_MCN },
177 { "CDTEXTFILE", K_TEXTFILE },
178 { "COMPOSER", K_COMPOSER }, /* Not supported by CDR-WIN */
179 { "FILE", K_FILE },
180 { "FLAGS", K_FLAGS },
181 { "INDEX", K_INDEX },
182 { "ISRC", K_ISRC },
183 { "MESSAGE", K_MESSAGE }, /* Not supported by CDR-WIN */
184 { "PERFORMER", K_PERFORMER },
185 { "POSTGAP", K_POSTGAP },
186 { "PREGAP", K_PREGAP },
187 { "REM", K_REM },
188 { "SONGWRITER", K_SONGWRITER },
189 { "TITLE", K_TITLE },
190 { "TRACK", K_TRACK },
191 { NULL, 0 },
192 };
193
194
195 /*
196 * Filetypes - argument to FILE Keyword (one only):
197 *
198 * BINARY - Intel binary file (least significant byte first)
199 * MOTOTOLA - Motorola binary file (most significant byte first)
200 * AIFF - Audio AIFF file
201 * WAVE - Audio WAVE file
202 * MP3 - Audio MP3 file
203 * AU - Sun Audio file
204 * OGG - Audio OGG file
205 */
206 #define K_BINARY 100
207 #define K_MOTOROLA 101
208 #define K_AIFF 102
209 #define K_WAVE 103
210 #define K_MP3 104
211 #define K_FT_CDRWIN_MAX 104
212 #define K_AU 105
213 #define K_OGG 106
214
215 LOCAL keyw_t filetypes[] = {
216 { "BINARY", K_BINARY },
217 { "MOTOROLA", K_MOTOROLA },
218 { "AIFF", K_AIFF },
219 { "WAVE", K_WAVE },
220 { "MP3", K_MP3 },
221 { "AU", K_AU }, /* Not supported by CDR-WIN */
222 { "OGG", K_OGG }, /* Not supported by CDR-WIN */
223 { NULL, 0 },
224 };
225
226 /*
227 * Flags - argument to FLAGS Keyword (more than one allowed):
228 * DCP - Digital copy permitted
229 * 4CH - Four channel audio
230 * PRE - Pre-emphasis enabled (audio tracks only)
231 * SCMS - Serial copy management system (not supported by all recorders)
232 */
233 #define K_DCP 1000
234 #define K_4CH 1001
235 #define K_PRE 1002
236 #define K_SCMS 1003
237 #define K_FL_CDRWIN_MAX 1003
238
239 LOCAL keyw_t flags[] = {
240 { "DCP", K_DCP },
241 { "4CH", K_4CH },
242 { "PRE", K_PRE },
243 { "SCMS", K_SCMS },
244 { NULL, 0 },
245 };
246
247 /*
248 * Datatypes - argument to TRACK Keyword (one only):
249 * AUDIO - Audio/Music (2352)
250 * CDG - Karaoke CD+G (2448)
251 * MODE1/2048 - CDROM Mode1 Data (cooked)
252 * MODE1/2352 - CDROM Mode1 Data (raw)
253 * MODE2/2336 - CDROM-XA Mode2 Data
254 * MODE2/2352 - CDROM-XA Mode2 Data
255 * CDI/2336 - CDI Mode2 Data
256 * CDI/2352 - CDI Mode2 Data
257 */
258 #define K_AUDIO 10000
259 #define K_CDG 10001
260 #define K_MODE1 10002
261 #define K_MODE2 10003
262 #define K_CDI 10004
263 #define K_DT_CDRWIN_MAX 10004
264
265 LOCAL keyw_t dtypes[] = {
266 { "AUDIO", K_AUDIO },
267 { "CDG", K_CDG },
268 { "MODE1", K_MODE1 },
269 { "MODE2", K_MODE2 },
270 { "CDI", K_CDI },
271 { NULL, 0 },
272 };
273
274
275 #ifdef CUE_MAIN
276 EXPORT int main __PR((int ac, char **av));
277 #endif
278 EXPORT int parsecue __PR((char *cuefname, track_t trackp[]));
279 EXPORT void fparsecue __PR((FILE *f, track_t trackp[]));
280 LOCAL void parse_arranger __PR((track_t trackp[], state_t *sp));
281 LOCAL void parse_mcn __PR((track_t trackp[], state_t *sp));
282 LOCAL void parse_textfile __PR((track_t trackp[], state_t *sp));
283 LOCAL void parse_composer __PR((track_t trackp[], state_t *sp));
284 LOCAL void parse_file __PR((track_t trackp[], state_t *sp));
285 LOCAL void parse_flags __PR((track_t trackp[], state_t *sp));
286 LOCAL void parse_index __PR((track_t trackp[], state_t *sp));
287 LOCAL void parse_isrc __PR((track_t trackp[], state_t *sp));
288 LOCAL void parse_message __PR((track_t trackp[], state_t *sp));
289 LOCAL void parse_performer __PR((track_t trackp[], state_t *sp));
290 LOCAL void parse_postgap __PR((track_t trackp[], state_t *sp));
291 LOCAL void parse_pregap __PR((track_t trackp[], state_t *sp));
292 LOCAL void parse_rem __PR((track_t trackp[], state_t *sp));
293 LOCAL void parse_songwriter __PR((track_t trackp[], state_t *sp));
294 LOCAL void parse_title __PR((track_t trackp[], state_t *sp));
295 LOCAL void parse_track __PR((track_t trackp[], state_t *sp));
296 LOCAL void parse_offset __PR((long *lp));
297 LOCAL void newtrack __PR((track_t trackp[], state_t *sp));
298
299 LOCAL keyw_t *lookup __PR((char *word, keyw_t table[]));
300 LOCAL char *state_name __PR((int st));
301 #ifdef DEBUG
302 LOCAL void wdebug __PR((void));
303 #endif
304 LOCAL FILE *cueopen __PR((char *name));
305 LOCAL char *cuename __PR((void));
306 LOCAL char *nextline __PR((FILE *f));
307 #ifdef __needed__
308 LOCAL void ungetline __PR((void));
309 #endif
310 LOCAL char *skipwhite __PR((const char *s));
311 LOCAL char *peekword __PR((void));
312 LOCAL char *lineend __PR((void));
313 LOCAL char *markword __PR((char *delim));
314 LOCAL char getworddelim __PR((void));
315 LOCAL char *getnextitem __PR((char *delim));
316 LOCAL char *neednextitem __PR((char *delim, char *type));
317 #ifdef __needed__
318 LOCAL char *nextword __PR((void));
319 #endif
320 LOCAL char *needword __PR((char *type));
321 LOCAL char *curword __PR((void));
322 LOCAL char *nextitem __PR((void));
323 LOCAL char *needitem __PR((char *type));
324 LOCAL void checkextra __PR((void));
325 LOCAL void statewarn __PR((state_t *sp, const char *fmt, ...));
326 #ifdef __needed__
327 LOCAL void cuewarn __PR((const char *fmt, ...));
328 #endif
329 LOCAL void cueabort __PR((const char *fmt, ...));
330 LOCAL void extabort __PR((const char *fmt, ...));
331
332 #ifdef CUE_MAIN
333 int debug;
334 int xdebug = 1;
335
336 int write_secs __PR((void));
write_secs()337 int write_secs() { return (-1); }
338
339 EXPORT int
main(ac,av)340 main(ac, av)
341 int ac;
342 char *av[];
343 {
344 int i;
345 track_t track[MAX_TRACK+2]; /* Max tracks + track 0 + track AA */
346
347 save_args(ac, av);
348
349 fillbytes(track, sizeof (track), '\0');
350 for (i = 0; i < MAX_TRACK+2; i++)
351 track[i].track = track[i].trackno = i;
352 track[0].tracktype = TOC_MASK;
353
354
355 parsecue(av[1], track);
356 return (0);
357 }
358 #else
359 extern int xdebug;
360 #endif
361
362 EXPORT int
parsecue(cuefname,trackp)363 parsecue(cuefname, trackp)
364 char *cuefname;
365 track_t trackp[];
366 {
367 FILE *f = cueopen(cuefname);
368
369 fparsecue(f, trackp);
370 return (0);
371 }
372
373 EXPORT void
fparsecue(f,trackp)374 fparsecue(f, trackp)
375 FILE *f;
376 track_t trackp[];
377 {
378 char *word;
379 struct keyw *kp;
380 BOOL isglobal = TRUE;
381 state_t state;
382
383 state.filename = NULL;
384 state.xfp = NULL;
385 state.trackoff = 0;
386 state.filesize = 0;
387 state.filetype = 0;
388 state.tracktype = 0;
389 state.sectype = 0;
390 state.dbtype = 0;
391 state.secsize = 0;
392 state.dataoff = 0;
393 state.state = STATE_NONE;
394 state.prevstate = STATE_NONE;
395 state.track = 0;
396 state.trackno = 0;
397 state.index = -1;
398 state.index0 = -1;
399 state.index1 = -1;
400 state.secoff = 0;
401 state.pregapsize = -1;
402 state.postgapsize = -1;
403 state.flags = 0;
404 state.pflags = 0;
405
406 if (xdebug > 1)
407 printf(_("---> Entering CUE Parser...\n"));
408 do {
409 if (nextline(f) == NULL) {
410 /*
411 * EOF on CUE File
412 * Do post processing here
413 */
414 if (state.state < STATE_INDEX1 && state.state != STATE_POSTGAP) {
415 statewarn(&state, _("INDEX 01 missing"));
416 cueabort(_("Incomplete CUE file"));
417 }
418 if (state.xfp) {
419 xclose(state.xfp);
420 state.xfp = NULL;
421 }
422 if (xdebug > 1) {
423 printf(_("---> CUE Parser got EOF, found %2.2d tracks.\n"),
424 state.track);
425 }
426 return;
427 }
428 word = nextitem();
429 if (*word == '\0') /* empty line */
430 continue;
431
432 if (xdebug > 1)
433 printf(_("\nKEY: '%s' %s\n"), word, peekword());
434 kp = lookup(word, keywords);
435 if (kp == NULL)
436 cueabort(_("Unknown CUE keyword '%s'"), word);
437
438 if ((kp->k_type & K_G) == 0) {
439 if (isglobal)
440 isglobal = FALSE;
441 }
442 if ((kp->k_type & K_T) == 0) {
443 if (!isglobal) {
444 statewarn(&state,
445 _("%s keyword must be before first TRACK"),
446 word);
447 cueabort(_("Badly placed CUE keyword '%s'"), word);
448 }
449 }
450 #ifdef DEBUG
451 printf("%s-", isglobal ? "G" : "T");
452 wdebug();
453 #endif
454
455 switch (kp->k_type) {
456
457 case K_ARRANGER: parse_arranger(trackp, &state); break;
458 case K_MCN: parse_mcn(trackp, &state); break;
459 case K_TEXTFILE: parse_textfile(trackp, &state); break;
460 case K_COMPOSER: parse_composer(trackp, &state); break;
461 case K_FILE: parse_file(trackp, &state); break;
462 case K_FLAGS: parse_flags(trackp, &state); break;
463 case K_INDEX: parse_index(trackp, &state); break;
464 case K_ISRC: parse_isrc(trackp, &state); break;
465 case K_MESSAGE: parse_message(trackp, &state); break;
466 case K_PERFORMER: parse_performer(trackp, &state); break;
467 case K_POSTGAP: parse_postgap(trackp, &state); break;
468 case K_PREGAP: parse_pregap(trackp, &state); break;
469 case K_REM: parse_rem(trackp, &state); break;
470 case K_SONGWRITER: parse_songwriter(trackp, &state); break;
471 case K_TITLE: parse_title(trackp, &state); break;
472 case K_TRACK: parse_track(trackp, &state); break;
473
474 default:
475 cueabort(_("Panic: unknown CUE command '%s'"), word);
476 }
477 } while (1);
478 }
479
480 LOCAL void
parse_arranger(trackp,sp)481 parse_arranger(trackp, sp)
482 track_t trackp[];
483 state_t *sp;
484 {
485 char *word;
486 textptr_t *txp;
487
488 if ((sp->pflags & PF_CDRTOOLS_EXT) == 0)
489 extabort("ARRANGER");
490
491 if (sp->track > 0 && sp->state > STATE_INDEX0) {
492 statewarn(sp, _("ARRANGER keyword cannot be after INDEX keyword"));
493 cueabort(_("Badly placed ARRANGER keyword"));
494 }
495
496 word = needitem("arranger");
497 txp = gettextptr(sp->track, trackp);
498 txp->tc_arranger = strdup(word);
499
500 checkextra();
501 }
502
503 LOCAL void
parse_mcn(trackp,sp)504 parse_mcn(trackp, sp)
505 track_t trackp[];
506 state_t *sp;
507 {
508 char *word;
509 textptr_t *txp;
510
511 if (sp->track != 0)
512 cueabort(_("CATALOG keyword must be before first TRACK"));
513
514 word = needitem("MCN");
515 setmcn(word, &trackp[0]);
516 txp = gettextptr(0, trackp); /* MCN is isrc for trk 0 */
517 txp->tc_isrc = strdup(word);
518
519 checkextra();
520 }
521
522 LOCAL void
parse_textfile(trackp,sp)523 parse_textfile(trackp, sp)
524 track_t trackp[];
525 state_t *sp;
526 {
527 char *word;
528
529 if (sp->track != 0)
530 cueabort(_("CDTEXTFILE keyword must be before first TRACK"));
531
532 word = needitem("cdtextfile");
533
534 if (trackp[MAX_TRACK+1].flags & TI_TEXT) {
535 if (!checktextfile(word)) {
536 comerrno(EX_BAD,
537 _("Cannot use '%s' as CD-Text file.\n"),
538 word);
539 }
540 trackp[0].flags |= TI_TEXT;
541 } else {
542 errmsgno(EX_BAD, _("Ignoring CDTEXTFILE '%s'.\n"), word);
543 errmsgno(EX_BAD, _("If you like to write CD-Text, call cdrecord -text.\n"));
544 }
545
546 checkextra();
547 }
548
549 LOCAL void
parse_composer(trackp,sp)550 parse_composer(trackp, sp)
551 track_t trackp[];
552 state_t *sp;
553 {
554 char *word;
555 textptr_t *txp;
556
557 if ((sp->pflags & PF_CDRTOOLS_EXT) == 0)
558 extabort("COMPOSER");
559
560 if (sp->track > 0 && sp->state > STATE_INDEX0) {
561 statewarn(sp, _("COMPOSER keyword cannot be after INDEX keyword"));
562 cueabort(_("Badly placed COMPOSER keyword"));
563 }
564
565 word = needitem("composer");
566 txp = gettextptr(sp->track, trackp);
567 txp->tc_composer = strdup(word);
568
569 checkextra();
570 }
571
572 LOCAL void
parse_file(trackp,sp)573 parse_file(trackp, sp)
574 track_t trackp[];
575 state_t *sp;
576 {
577 char cname[1024];
578 char newname[1024];
579 struct keyw *kp;
580 char *word;
581 char *filetype;
582 struct stat st;
583 #ifdef hint
584 Llong lsize;
585 #endif
586
587 if ((sp->state <= STATE_TRACK && sp->state > STATE_POSTGAP) ||
588 (sp->state >= STATE_TRACK && sp->state < STATE_INDEX1)) {
589 if (sp->state >= STATE_INDEX0 && sp->state < STATE_INDEX1) {
590 if ((sp->pflags & PF_CDRTOOLS_EXT) == 0)
591 extabort(_("FILE keyword after INDEX 00 and before INDEX 01"));
592 sp->prevstate = sp->state;
593 goto file_ok;
594 }
595 if (sp->state <= STATE_TRACK && sp->state > STATE_POSTGAP)
596 statewarn(sp, _("FILE keyword only allowed once before TRACK keyword"));
597 if (sp->state >= STATE_TRACK && sp->state < STATE_INDEX1)
598 statewarn(sp, _("FILE keyword not allowed after TRACK and before INDEX 01"));
599 cueabort(_("Badly placed FILE keyword"));
600 }
601 file_ok:
602 if (sp->state < STATE_INDEX1 && sp->pflags & PF_FILE_FOUND)
603 cueabort(_("Only one FILE keyword allowed per TRACK"));
604
605 sp->pflags |= PF_FILE_FOUND;
606 sp->state = STATE_FILE;
607
608 word = needitem("filename");
609 if (sp->xfp) {
610 xclose(sp->xfp);
611 sp->xfp = NULL;
612 }
613 sp->xfp = xopen(word, O_RDONLY|O_BINARY, 0, X_NOREWIND);
614 if (sp->xfp == NULL && geterrno() == ENOENT) {
615 char *p;
616
617 if (strchr(word, '/') == 0 &&
618 strchr(cuename(), '/') != 0) {
619 js_snprintf(cname, sizeof (cname),
620 "%s", cuename());
621 p = strrchr(cname, '/');
622 if (p)
623 *p = '\0';
624 js_snprintf(newname, sizeof (newname),
625 "%s/%s", cname, word);
626 word = newname;
627 sp->xfp = xopen(word, O_RDONLY|O_BINARY, 0, X_NOREWIND);
628 }
629 }
630 if (sp->xfp == NULL) {
631 #ifdef PARSE_DEBUG
632 errmsg(_("Cannot open FILE '%s'.\n"), word);
633 #else
634 comerr(_("Cannot open FILE '%s'.\n"), word);
635 #endif
636 }
637
638 sp->filename = strdup(word);
639 sp->trackoff = 0;
640 sp->secoff = 0;
641 sp->filesize = 0;
642 sp->flags &= ~TI_SWAB; /* Reset what we might set for FILE */
643
644 filetype = needitem("filetype");
645 kp = lookup(filetype, filetypes);
646 if (kp == NULL)
647 cueabort(_("Unknown filetype '%s'"), filetype);
648
649 if ((sp->pflags & PF_CDRTOOLS_EXT) == 0 &&
650 kp->k_type > K_FT_CDRWIN_MAX)
651 extabort(_("Filetype '%s'"), kp->k_name);
652
653 switch (kp->k_type) {
654
655 case K_BINARY:
656 case K_MOTOROLA:
657 if (fstat(xfileno(sp->xfp), &st) >= 0 &&
658 S_ISREG(st.st_mode)) {
659 sp->filesize = st.st_size;
660 if (kp->k_type == K_BINARY)
661 sp->flags |= TI_SWAB;
662 } else {
663 cueabort(_("Unknown file size for FILE '%s'"),
664 sp->filename);
665 }
666 break;
667 case K_AIFF:
668 cueabort(_("Unsupported filetype '%s'"), kp->k_name);
669 break;
670 case K_AU:
671 sp->filesize = ausize(xfileno(sp->xfp));
672 break;
673 case K_WAVE:
674 #ifdef PARSE_DEBUG
675 sp->filesize = 1000000000;
676 #else
677 sp->filesize = wavsize(xfileno(sp->xfp));
678 #endif
679 sp->flags |= TI_SWAB;
680 break;
681 case K_MP3:
682 case K_OGG:
683 cueabort(_("Unsupported filetype '%s'"), kp->k_name);
684 break;
685
686 default: cueabort(_("Panic: unknown filetype '%s'"), filetype);
687 }
688
689 if (sp->filesize == AU_BAD_CODING) {
690 cueabort(_("Inappropriate audio coding in '%s'"),
691 sp->filename);
692 }
693 if (xdebug > 0)
694 printf(_("Track[%2.2d] %2.2d File '%s' Filesize %lld\n"),
695 sp->track, sp->trackno, sp->filename, sp->filesize);
696
697 sp->filetype = kp->k_type;
698
699 checkextra();
700
701
702 #ifdef hint
703 trackp->itracksize = lsize;
704 if (trackp->itracksize != lsize)
705 comerrno(EX_BAD, _("This OS cannot handle large audio images.\n"));
706 #endif
707 }
708
709 LOCAL void
parse_flags(trackp,sp)710 parse_flags(trackp, sp)
711 track_t trackp[];
712 state_t *sp;
713 {
714 struct keyw *kp;
715 char *word;
716
717 if ((sp->state < STATE_TRACK) ||
718 (sp->state >= STATE_INDEX0)) {
719 statewarn(sp, _("FLAGS keyword must be after TRACK and before INDEX keyword"));
720 cueabort(_("Badly placed FLAGS keyword"));
721 }
722 sp->state = STATE_FLAGS;
723
724 do {
725 word = needitem("flag");
726 kp = lookup(word, flags);
727 if (kp == NULL)
728 cueabort(_("Unknown flag '%s'"), word);
729
730 switch (kp->k_type) {
731
732 case K_DCP: sp->flags |= TI_COPY; break;
733 case K_4CH: sp->flags |= TI_QUADRO; break;
734 case K_PRE: sp->flags |= TI_PREEMP; break;
735 case K_SCMS: sp->flags |= TI_SCMS; break;
736 default: cueabort(_("Panic: unknown FLAG '%s'"), word);
737 }
738
739 } while (peekword() < lineend());
740
741 if (xdebug > 0)
742 printf(_("Track[%2.2d] %2.2d flags 0x%08X\n"), sp->track, sp->trackno, sp->flags);
743 }
744
745 LOCAL void
parse_index(trackp,sp)746 parse_index(trackp, sp)
747 track_t trackp[];
748 state_t *sp;
749 {
750 char *word;
751 long l;
752 int track = sp->track;
753
754 if (sp->state < STATE_TRACK) {
755 if (sp->state == STATE_FILE &&
756 sp->prevstate >= STATE_TRACK &&
757 sp->prevstate <= STATE_INDEX1) {
758 if ((sp->pflags & PF_CDRTOOLS_EXT) == 0)
759 extabort(_("INDEX keyword after FILE keyword"));
760 goto index_ok;
761 }
762 statewarn(sp, _("INDEX keyword must be after TRACK keyword"));
763 cueabort(_("Badly placed INDEX keyword"));
764 }
765 index_ok:
766
767 word = needitem("index");
768 if (*astolb(word, &l, 10) != '\0')
769 cueabort(_("Not a number '%s'"), word);
770 if (l < 0 || l > 99)
771 cueabort(_("Illegal index '%s'"), word);
772
773 if ((sp->index < l) &&
774 (((sp->index + 1) == l) || l == 1))
775 sp->index = l;
776 else
777 cueabort(_("Badly placed INDEX %2.2ld number"), l);
778
779 if (sp->state == STATE_FILE) {
780 if (track == 1 || l > 1)
781 cueabort(_("INDEX %2.2d not allowed after FILE"), l);
782 if (l == 1)
783 sp->pflags |= PF_INDEX0_PREV;
784 }
785
786 if (l > 0)
787 sp->state = STATE_INDEX1;
788 else
789 sp->state = STATE_INDEX0;
790 sp->prevstate = sp->state;
791
792 parse_offset(&l);
793
794 if (xdebug > 1)
795 printf(_("Track[%2.2d] %2.2d Index %2.2d %ld\n"), sp->track, sp->trackno, sp->index, l);
796
797 if (track == 1 ||
798 !streql(sp->filename, trackp[track-1].filename)) {
799 /*
800 * Check for offset 0 when a new file begins.
801 */
802 if (sp->index == 0 && l > 0)
803 cueabort(_("Bad INDEX 00 offset in CUE file (must be 00:00:00 for new FILE)"));
804 if (sp->index == 1 && sp->index0 < 0 && l > 0)
805 cueabort(_("Bad INDEX 01 offset in CUE file (must be 00:00:00 for new FILE)"));
806 }
807
808 if (sp->index == 0) {
809 sp->index0 = l;
810 } else if (sp->index == 1) {
811 sp->index1 = l;
812 trackp[track].nindex = 1;
813 newtrack(trackp, sp);
814
815 if (xdebug > 1) {
816 printf(_("Track[%2.2d] %2.2d pregapsize %ld\n"),
817 sp->track, sp->trackno, trackp[track].pregapsize);
818 }
819 } else if (sp->index == 2) {
820 trackp[track].tindex = malloc(100*sizeof (long));
821 trackp[track].tindex[1] = 0;
822 trackp[track].tindex[2] = l - sp->index1;
823 trackp[track].nindex = 2;
824 } else if (sp->index > 2) {
825 trackp[track].tindex[sp->index] = l - sp->index1;
826 trackp[track].nindex = sp->index;
827 }
828
829 checkextra();
830 }
831
832 LOCAL void
parse_isrc(trackp,sp)833 parse_isrc(trackp, sp)
834 track_t trackp[];
835 state_t *sp;
836 {
837 char *word;
838 textptr_t *txp;
839 int track = sp->track;
840
841 if (track == 0)
842 cueabort(_("ISRC keyword must be past first TRACK"));
843
844 if ((sp->state < STATE_TRACK) ||
845 (sp->state >= STATE_INDEX0)) {
846 statewarn(sp, _("ISRC keyword must be after TRACK and before INDEX keyword"));
847 cueabort(_("Badly placed ISRC keyword"));
848 }
849 sp->state = STATE_FLAGS;
850
851 word = needitem("ISRC");
852 if ((sp->pflags & PF_CDRTOOLS_EXT) == 0 &&
853 strchr(word, '-')) {
854 extabort(_("'-' in ISRC arg"));
855 }
856 setisrc(word, &trackp[track]);
857 txp = gettextptr(track, trackp);
858 txp->tc_isrc = strdup(word);
859
860 checkextra();
861 }
862
863 LOCAL void
parse_message(trackp,sp)864 parse_message(trackp, sp)
865 track_t trackp[];
866 state_t *sp;
867 {
868 char *word;
869 textptr_t *txp;
870
871 if ((sp->pflags & PF_CDRTOOLS_EXT) == 0)
872 extabort("MESSAGE");
873
874 if (sp->track > 0 && sp->state > STATE_INDEX0) {
875 statewarn(sp, _("MESSAGE keyword cannot be after INDEX keyword"));
876 cueabort(_("Badly placed MESSAGE keyword"));
877 }
878
879 word = needitem("message");
880 txp = gettextptr(sp->track, trackp);
881 txp->tc_message = strdup(word);
882
883 checkextra();
884 }
885
886 LOCAL void
parse_performer(trackp,sp)887 parse_performer(trackp, sp)
888 track_t trackp[];
889 state_t *sp;
890 {
891 char *word;
892 textptr_t *txp;
893
894 if (sp->track > 0 && sp->state > STATE_INDEX0) {
895 statewarn(sp, _("PERFORMER keyword cannot be after INDEX keyword"));
896 cueabort(_("Badly placed PERFORMER keyword"));
897 }
898
899 word = needitem("performer");
900 txp = gettextptr(sp->track, trackp);
901 txp->tc_performer = strdup(word);
902
903 checkextra();
904 }
905
906 LOCAL void
parse_postgap(trackp,sp)907 parse_postgap(trackp, sp)
908 track_t trackp[];
909 state_t *sp;
910 {
911 long l;
912
913 if (sp->state < STATE_INDEX1) {
914 statewarn(sp, _("POSTGAP keyword must be after INDEX 01"));
915 cueabort(_("Badly placed POSTGAP keyword"));
916 }
917 sp->state = STATE_POSTGAP;
918
919 parse_offset(&l);
920 sp->postgapsize = l;
921 trackp[sp->track].padsecs = l;
922 /*
923 * Add to size of track.
924 * In non-CUE mode, this is done in opentracks().
925 */
926 if (l > 0)
927 trackp[sp->track].tracksecs += l;
928
929 checkextra();
930 }
931
932 LOCAL void
parse_pregap(trackp,sp)933 parse_pregap(trackp, sp)
934 track_t trackp[];
935 state_t *sp;
936 {
937 long l;
938
939 if ((sp->state < STATE_TRACK) ||
940 (sp->state >= STATE_INDEX0)) {
941 statewarn(sp, _("PREGAP keyword must be after TRACK and before INDEX keyword"));
942 cueabort(_("Badly placed PREGAP keyword"));
943 }
944 sp->state = STATE_FLAGS;
945
946 parse_offset(&l);
947 sp->pregapsize = l;
948
949 checkextra();
950 }
951
952 LOCAL void
parse_rem(trackp,sp)953 parse_rem(trackp, sp)
954 track_t trackp[];
955 state_t *sp;
956 {
957 char *oword = curword();
958 char *word;
959
960 word = nextitem();
961 if ((oword == word) || (*word == '\0'))
962 return;
963 if ((sp->pflags & PF_CDRTOOLS_EXT) == 0 &&
964 streql(word, "CDRTOOLS")) {
965 sp->pflags |= PF_CDRTOOLS_EXT;
966 errmsgno(EX_BAD,
967 _("Warning: Enabling cdrecord specific CUE extensions.\n"));
968 }
969 if ((sp->pflags & PF_CDRTOOLS_EXT) == 0 &&
970 streql(word, "COMMENT")) {
971 oword = word;
972 word = nextitem();
973 if ((oword == word) || (*word == '\0'))
974 return;
975 if (strncmp(word, "ExactAudioCopy ", 15) == 0) {
976 sp->pflags |= PF_CDRTOOLS_EXT;
977 errmsgno(EX_BAD,
978 _("Warning: Found ExactAudioCopy, enabling CUE extensions.\n"));
979 }
980 }
981 }
982
983 LOCAL void
parse_songwriter(trackp,sp)984 parse_songwriter(trackp, sp)
985 track_t trackp[];
986 state_t *sp;
987 {
988 char *word;
989 textptr_t *txp;
990
991 if (sp->track > 0 && sp->state > STATE_INDEX0) {
992 statewarn(sp, _("SONGWRITER keyword cannot be after INDEX keyword"));
993 cueabort(_("Badly placed SONGWRITER keyword"));
994 }
995 word = needitem("songwriter");
996 txp = gettextptr(sp->track, trackp);
997 txp->tc_songwriter = strdup(word);
998
999 checkextra();
1000 }
1001
1002 LOCAL void
parse_title(trackp,sp)1003 parse_title(trackp, sp)
1004 track_t trackp[];
1005 state_t *sp;
1006 {
1007 char *word;
1008 textptr_t *txp;
1009
1010 if (sp->track > 0 && sp->state > STATE_INDEX0) {
1011 statewarn(sp, _("TITLE keyword cannot be after INDEX keyword"));
1012 cueabort(_("Badly placed TITLE keyword"));
1013 }
1014 word = needitem("title");
1015 txp = gettextptr(sp->track, trackp);
1016 txp->tc_title = strdup(word);
1017
1018 checkextra();
1019 }
1020
1021 LOCAL void
parse_track(trackp,sp)1022 parse_track(trackp, sp)
1023 track_t trackp[];
1024 state_t *sp;
1025 {
1026 struct keyw *kp;
1027 char *word;
1028 long l;
1029 long secsize = -1;
1030
1031 if ((sp->state >= STATE_TRACK) &&
1032 (sp->state < STATE_INDEX1)) {
1033 statewarn(sp, _("TRACK keyword must be after INDEX 01"));
1034 cueabort(_("Badly placed TRACK keyword"));
1035 }
1036 sp->pflags &= ~(PF_INDEX0_PREV|PF_FILE_FOUND);
1037 if (sp->state == STATE_FILE)
1038 sp->pflags |= PF_FILE_FOUND;
1039 sp->state = STATE_TRACK;
1040 sp->prevstate = STATE_TRACK;
1041 sp->track++;
1042 sp->index0 = -1;
1043 sp->index = -1;
1044 sp->pregapsize = -1;
1045 sp->postgapsize = -1;
1046
1047 word = needitem("track number");
1048 if (*astolb(word, &l, 10) != '\0')
1049 cueabort(_("Not a number '%s'"), word);
1050 if (l <= 0 || l > 99)
1051 cueabort(_("Illegal TRACK number '%s'"), word);
1052
1053 if ((sp->trackno < l) &&
1054 (((sp->trackno + 1) == l) || sp->trackno == 0))
1055 sp->trackno = l;
1056 else
1057 cueabort(_("Badly placed TRACK %ld number"), l);
1058
1059 word = needword("data type");
1060 kp = lookup(word, dtypes);
1061 if (kp == NULL)
1062 cueabort(_("Unknown data type '%s'"), word);
1063
1064 if (getworddelim() == '/') {
1065 word = needitem("sector size");
1066 if (*astol(++word, &secsize) != '\0')
1067 cueabort(_("Not a number '%s'"), word);
1068 }
1069
1070 /*
1071 * Reset all flags that may be set in TRACK & FLAGS lines
1072 */
1073 sp->flags &= ~(TI_AUDIO|TI_COPY|TI_QUADRO|TI_PREEMP|TI_SCMS);
1074
1075 if (kp->k_type == K_AUDIO)
1076 sp->flags |= TI_AUDIO;
1077
1078 switch (kp->k_type) {
1079
1080 case K_CDG:
1081 if (secsize < 0)
1082 secsize = 2448;
1083 /* FALLTHROUGH */
1084 case K_AUDIO:
1085 if (secsize < 0)
1086 secsize = 2352;
1087
1088 sp->tracktype = TOC_DA;
1089 sp->sectype = SECT_AUDIO;
1090 sp->dbtype = DB_RAW;
1091 sp->secsize = secsize;
1092 sp->dataoff = 0;
1093 if (secsize != 2352)
1094 cueabort(_("Unsupported sector size %ld for audio"), secsize);
1095 break;
1096
1097 case K_MODE1:
1098 if (secsize < 0)
1099 secsize = 2048;
1100
1101 sp->tracktype = TOC_ROM;
1102 sp->sectype = SECT_ROM;
1103 sp->dbtype = DB_ROM_MODE1;
1104 sp->secsize = secsize;
1105 sp->dataoff = 16;
1106 /*
1107 * XXX Sector Size == 2352 ???
1108 * XXX It seems that there exist bin/cue pairs with this value
1109 */
1110 if (secsize != 2048)
1111 cueabort(_("Unsupported sector size %ld for data"), secsize);
1112 break;
1113
1114 case K_MODE2:
1115 case K_CDI:
1116 sp->tracktype = TOC_ROM;
1117 sp->sectype = SECT_MODE_2;
1118 sp->dbtype = DB_ROM_MODE2;
1119 sp->secsize = secsize;
1120 sp->dataoff = 16;
1121 if (secsize == 2352) {
1122 sp->tracktype = TOC_XA2;
1123 sp->sectype = SECT_MODE_2_MIX;
1124 sp->sectype |= ST_MODE_RAW;
1125 sp->dbtype = DB_RAW;
1126 sp->dataoff = 0;
1127 } else if (secsize != 2336)
1128 cueabort(_("Unsupported sector size %ld for mode2"), secsize);
1129 if (kp->k_type == K_CDI)
1130 sp->tracktype = TOC_CDI;
1131 break;
1132
1133 default: cueabort(_("Panic: unknown datatype '%s'"), word);
1134 }
1135
1136 if (sp->flags & TI_PREEMP)
1137 sp->sectype |= ST_PREEMPMASK;
1138 sp->secsize = secsize;
1139
1140 if (xdebug > 1) {
1141 printf(_("Track[%2.2d] %2.2d Tracktype %s/%d\n"),
1142 sp->track, sp->trackno, kp->k_name, sp->secsize);
1143 }
1144
1145 checkextra();
1146 }
1147
1148 LOCAL void
parse_offset(lp)1149 parse_offset(lp)
1150 long *lp;
1151 {
1152 char *word;
1153 char *p;
1154 long m = -1;
1155 long s = -1;
1156 long f = -1;
1157
1158 word = needitem("time offset/length");
1159
1160 if (strchr(word, ':') == NULL) {
1161 if (*astol(word, lp) != '\0')
1162 cueabort(_("Not a number '%s'"), word);
1163 return;
1164 }
1165 if (*(p = astolb(word, &m, 10)) != ':')
1166 cueabort(_("Not a number '%s'"), word);
1167 if (m < 0 || m >= 160)
1168 cueabort(_("Illegal minute value in '%s'"), word);
1169 p++;
1170 if (*(p = astolb(p, &s, 10)) != ':')
1171 cueabort(_("Not a number '%s'"), p);
1172 if (s < 0 || s >= 60)
1173 cueabort(_("Illegal second value in '%s'"), word);
1174 p++;
1175 if (*(p = astolb(p, &f, 10)) != '\0')
1176 cueabort(_("Not a number '%s'"), p);
1177 if (f < 0 || f >= 75)
1178 cueabort(_("Illegal frame value in '%s'"), word);
1179
1180 m = m * 60 + s;
1181 m = m * 75 + f;
1182 *lp = m;
1183 }
1184
1185 /*--------------------------------------------------------------------------*/
1186 LOCAL void
newtrack(trackp,sp)1187 newtrack(trackp, sp)
1188 track_t trackp[];
1189 state_t *sp;
1190 {
1191 register int i;
1192 register int track = sp->track;
1193 Llong tracksize;
1194
1195 if (xdebug > 1)
1196 printf(_("-->Newtrack %2.2d Trackno %2.2d\n"), track, sp->trackno);
1197 if (track > 1 && streql(sp->filename, trackp[track-1].filename)) {
1198 tracksize = (sp->index1 - sp->secoff) * trackp[track-1].isecsize;
1199
1200 if (xdebug > 1)
1201 printf(" trackoff %lld filesize %lld index1 %ld size %ld/%lld secsize/isecsize %d/%d\n",
1202 sp->trackoff, sp->filesize, sp->index1,
1203 sp->index1 - sp->secoff,
1204 tracksize,
1205 trackp[track-1].secsize,
1206 trackp[track-1].isecsize);
1207
1208 trackp[track-1].itracksize = tracksize;
1209 trackp[track-1].tracksize = tracksize;
1210 if (trackp[track-1].secsize != trackp[track-1].isecsize) {
1211 /*
1212 * In RAW mode, we need to recompute the track size.
1213 */
1214 trackp[track-1].tracksize =
1215 (trackp[track-1].itracksize /
1216 trackp[track-1].isecsize) *
1217 trackp[track-1].secsize
1218 + trackp[track-1].itracksize %
1219 trackp[track-1].isecsize;
1220 }
1221 trackp[track-1].tracksecs = sp->index1 - sp->secoff;
1222 /*
1223 * Add to size of track.
1224 * In non-CUE mode, this is done in opentracks().
1225 */
1226 if (trackp[track-1].padsecs > 0)
1227 trackp[track-1].tracksecs += trackp[track-1].padsecs;
1228
1229 sp->trackoff += tracksize;
1230 sp->secoff = sp->index1;
1231 }
1232 /*
1233 * Make 'tracks' immediately usable in track structure.
1234 */
1235 for (i = 0; i < MAX_TRACK+2; i++)
1236 trackp[i].tracks = track;
1237
1238 trackp[track].filename = sp->filename;
1239 trackp[track].xfp = xopen(sp->filename, O_RDONLY|O_BINARY, 0, X_NOREWIND);
1240 trackp[track].trackstart = 0L;
1241 /*
1242 * SEtzen wenn tracksecs bekannt sind
1243 * d.h. mit Index0 oder Index 1 vom n�chsten track
1244 *
1245 * trackp[track].itracksize = tracksize;
1246 * trackp[track].tracksize = tracksize;
1247 * trackp[track].tracksecs = -1L;
1248 */
1249 tracksize = sp->filesize - sp->trackoff;
1250
1251 trackp[track].itracksize = tracksize;
1252 trackp[track].tracksize = tracksize;
1253 trackp[track].tracksecs = (tracksize + sp->secsize - 1) / sp->secsize;
1254
1255 if (xdebug > 1)
1256 printf(_(" Remaining Filesize %lld (%lld secs)\n"),
1257 (sp->filesize-sp->trackoff),
1258 (sp->filesize-sp->trackoff +sp->secsize - 1) / sp->secsize);
1259
1260 if (sp->pregapsize >= 0) {
1261 /* trackp[track].flags &= ~TI_PREGAP;*/
1262 sp->flags &= ~TI_PREGAP;
1263 trackp[track].pregapsize = sp->pregapsize;
1264 } else {
1265 /* trackp[track].flags |= TI_PREGAP;*/
1266 if (track > 1)
1267 sp->flags |= TI_PREGAP;
1268 if (track == 1)
1269 trackp[track].pregapsize = sp->index1 + 150;
1270 else if (sp->index0 < 0)
1271 trackp[track].pregapsize = 0;
1272 else if (sp->pflags & PF_INDEX0_PREV) /* INDEX0 in prev FILE */
1273 trackp[track].pregapsize = trackp[track-1].tracksecs - sp->index0;
1274 else
1275 trackp[track].pregapsize = sp->index1 - sp->index0;
1276 }
1277
1278 trackp[track].isecsize = sp->secsize;
1279 trackp[track].secsize = sp->secsize;
1280 trackp[track].flags = sp->flags |
1281 (trackp[0].flags & ~(TI_HIDDEN|TI_SWAB|TI_AUDIO|TI_COPY|TI_QUADRO|TI_PREEMP|TI_SCMS));
1282 if (trackp[0].flags & TI_RAW) {
1283 if (is_raw16(&trackp[track]))
1284 trackp[track].secsize = RAW16_SEC_SIZE;
1285 else
1286 trackp[track].secsize = RAW96_SEC_SIZE;
1287 #ifndef HAVE_LIB_EDC_ECC
1288 if ((sp->sectype & ST_MODE_MASK) != ST_MODE_AUDIO) {
1289 errmsgno(EX_BAD,
1290 _("EDC/ECC library not compiled in.\n"));
1291 comerrno(EX_BAD,
1292 _("Data sectors are not supported in RAW mode.\n"));
1293 }
1294 #endif
1295 }
1296 /*
1297 * In RAW mode, we need to recompute the track size.
1298 */
1299 trackp[track].tracksize =
1300 (trackp[track].itracksize / trackp[track].isecsize) *
1301 trackp[track].secsize
1302 + trackp[track].itracksize % trackp[track].isecsize;
1303
1304 trackp[track].secspt = 0; /* transfer size is set up in set_trsizes() */
1305 /* trackp[track].pktsize = pktsize; */
1306 trackp[track].pktsize = 0;
1307 trackp[track].trackno = sp->trackno;
1308 trackp[track].sectype = sp->sectype;
1309
1310 trackp[track].dataoff = sp->dataoff;
1311 trackp[track].tracktype = sp->tracktype;
1312 trackp[track].dbtype = sp->dbtype;
1313
1314 if (track == 1) {
1315 track_t *tp0 = &trackp[0];
1316 track_t *tp1 = &trackp[1];
1317
1318 tp0->tracktype &= ~TOC_MASK;
1319 tp0->tracktype |= sp->tracktype;
1320
1321 /*
1322 * setleadinout() also sets: sectype dbtype dataoff
1323 */
1324 tp0->sectype = tp1->sectype;
1325 tp0->dbtype = tp1->dbtype;
1326 tp0->dataoff = tp1->dataoff;
1327 tp0->isecsize = tp1->isecsize;
1328 tp0->secsize = tp1->secsize;
1329
1330 if (sp->index0 == 0 && sp->index1 > 0) {
1331
1332 tp0->filename = tp1->filename;
1333 tp0->xfp = xopen(sp->filename, O_RDONLY|O_BINARY, 0, X_NOREWIND);
1334 tp0->trackstart = tp1->trackstart;
1335 tp0->itracksize = sp->index1 * tp1->isecsize;
1336 tp0->tracksize = sp->index1 * tp1->secsize;
1337 tp0->tracksecs = sp->index1;
1338 tp1->tracksecs -= sp->index1;
1339 sp->secoff += sp->index1;
1340 sp->trackoff += sp->index1 * tp1->isecsize;
1341 tp1->flags &= ~TI_PREGAP;
1342 tp0->flags |= tp1->flags &
1343 (TI_SWAB|TI_AUDIO|TI_COPY|TI_QUADRO|TI_PREEMP|TI_SCMS);
1344 tp0->flags |= TI_HIDDEN;
1345 tp1->flags |= TI_HIDDEN;
1346 }
1347
1348 if (xdebug > 1) {
1349 printf(_("Track[%2.2d] %2.2d Tracktype %X\n"),
1350 0, 0, trackp[0].tracktype);
1351 }
1352 }
1353 if (xdebug > 1) {
1354 printf(_("Track[%2.2d] %2.2d Tracktype %X\n"),
1355 track, sp->trackno, trackp[track].tracktype);
1356 }
1357 trackp[track].nindex = 1;
1358 trackp[track].tindex = 0;
1359
1360 if (xdebug > 1) {
1361 printf(_("Track[%2.2d] %2.2d flags 0x%08X\n"), 0, 0, trackp[0].flags);
1362 printf(_("Track[%2.2d] %2.2d flags 0x%08X\n"), track, sp->trackno, trackp[track].flags);
1363 }
1364 }
1365
1366 /*--------------------------------------------------------------------------*/
1367 LOCAL keyw_t *
lookup(word,table)1368 lookup(word, table)
1369 char *word;
1370 keyw_t table[];
1371 {
1372 register keyw_t *kp = table;
1373
1374 while (kp->k_name) {
1375 if (streql(kp->k_name, word))
1376 return (kp);
1377 kp++;
1378 }
1379 return (NULL);
1380 }
1381
1382 LOCAL char *
state_name(st)1383 state_name(st)
1384 int st;
1385 {
1386 if (st < STATE_NONE || st > STATE_MAX)
1387 return ("UNKNOWN");
1388 return (states[st]);
1389 }
1390
1391 /*--------------------------------------------------------------------------*/
1392 /*
1393 * Parser low level functions start here...
1394 */
1395
1396 LOCAL char linebuf[4096];
1397 LOCAL char *fname;
1398 LOCAL char *linep;
1399 LOCAL char *wordendp;
1400 LOCAL char wordendc;
1401 LOCAL int olinelen;
1402 LOCAL int linelen;
1403 LOCAL int lineno;
1404
1405 LOCAL char worddelim[] = "=:,/";
1406 LOCAL char nulldelim[] = "";
1407
1408 #ifdef DEBUG
1409 LOCAL void
wdebug()1410 wdebug()
1411 {
1412 printf("WORD: '%s' rest '%s'\n", linep, peekword());
1413 printf("linep %lX peekword %lX end %lX\n",
1414 (long)linep, (long)peekword(), (long)&linebuf[linelen]);
1415 }
1416 #endif
1417
1418 LOCAL FILE *
cueopen(name)1419 cueopen(name)
1420 char *name;
1421 {
1422 FILE *f;
1423
1424 f = fileopen(name, "r");
1425 if (f == NULL)
1426 comerr(_("Cannot open '%s'.\n"), name);
1427
1428 fname = name;
1429 return (f);
1430 }
1431
1432 LOCAL char *
cuename()1433 cuename()
1434 {
1435 return (fname);
1436 }
1437
1438 LOCAL char *
nextline(f)1439 nextline(f)
1440 FILE *f;
1441 {
1442 register int len;
1443
1444 do {
1445 fillbytes(linebuf, sizeof (linebuf), '\0');
1446 len = fgetline(f, linebuf, sizeof (linebuf));
1447 if (len < 0)
1448 return (NULL);
1449 if (len > 0 && linebuf[len-1] == '\r') {
1450 linebuf[len-1] = '\0';
1451 len--;
1452 }
1453 linelen = len;
1454 lineno++;
1455 } while (linebuf[0] == '#');
1456
1457 olinelen = linelen;
1458 linep = linebuf;
1459 wordendp = linep;
1460 wordendc = *linep;
1461
1462 return (linep);
1463 }
1464
1465 #ifdef __needed__
1466 LOCAL void
ungetline()1467 ungetline()
1468 {
1469 linelen = olinelen;
1470 linep = linebuf;
1471 *wordendp = wordendc;
1472 wordendp = linep;
1473 wordendc = *linep;
1474 }
1475 #endif
1476
1477 LOCAL char *
skipwhite(s)1478 skipwhite(s)
1479 const char *s;
1480 {
1481 register const Uchar *p = (const Uchar *)s;
1482
1483 while (*p) {
1484 if (!isspace(*p))
1485 break;
1486 p++;
1487 }
1488 return ((char *)p);
1489 }
1490
1491 LOCAL char *
peekword()1492 peekword()
1493 {
1494 return (&wordendp[1]);
1495 }
1496
1497 LOCAL char *
lineend()1498 lineend()
1499 {
1500 return (&linebuf[linelen]);
1501 }
1502
1503 LOCAL char *
markword(delim)1504 markword(delim)
1505 char *delim;
1506 {
1507 register BOOL quoted = FALSE;
1508 register Uchar c;
1509 register Uchar *s;
1510 register Uchar *from;
1511 register Uchar *to;
1512
1513 for (s = (Uchar *)linep; (c = *s) != '\0'; s++) {
1514 if (c == '"') {
1515 quoted = !quoted;
1516 for (to = s, from = &s[1]; *from; ) {
1517 c = *from++;
1518 if (c == '\\' && quoted && (*from == '\\' || *from == '"'))
1519 c = *from++;
1520 *to++ = c;
1521 }
1522 *to = '\0';
1523 c = *s;
1524 linelen--;
1525 }
1526 if (!quoted && isspace(c))
1527 break;
1528 if (!quoted && strchr(delim, c) && s > (Uchar *)linep)
1529 break;
1530 }
1531 wordendp = (char *)s;
1532 wordendc = (char)*s;
1533 *s = '\0';
1534
1535 return (linep);
1536 }
1537
1538 LOCAL char
getworddelim()1539 getworddelim()
1540 {
1541 return (wordendc);
1542 }
1543
1544 LOCAL char *
getnextitem(delim)1545 getnextitem(delim)
1546 char *delim;
1547 {
1548 *wordendp = wordendc;
1549
1550 linep = skipwhite(wordendp);
1551 return (markword(delim));
1552 }
1553
1554 LOCAL char *
neednextitem(delim,type)1555 neednextitem(delim, type)
1556 char *delim;
1557 char *type;
1558 {
1559 char *olinep = linep;
1560 char *nlinep;
1561
1562 nlinep = getnextitem(delim);
1563
1564 if ((olinep == nlinep) || (*nlinep == '\0')) {
1565 if (type == NULL)
1566 cueabort(_("Missing text"));
1567 else
1568 cueabort(_("Missing '%s'"), type);
1569 }
1570
1571 return (nlinep);
1572 }
1573
1574 #ifdef __needed__
1575 LOCAL char *
nextword()1576 nextword()
1577 {
1578 return (getnextitem(worddelim));
1579 }
1580 #endif
1581
1582 LOCAL char *
needword(type)1583 needword(type)
1584 char *type;
1585 {
1586 return (neednextitem(worddelim, type));
1587 }
1588
1589 LOCAL char *
curword()1590 curword()
1591 {
1592 return (linep);
1593 }
1594
1595 LOCAL char *
nextitem()1596 nextitem()
1597 {
1598 return (getnextitem(nulldelim));
1599 }
1600
1601 LOCAL char *
needitem(type)1602 needitem(type)
1603 char *type;
1604 {
1605 return (neednextitem(nulldelim, type));
1606 }
1607
1608 LOCAL void
checkextra()1609 checkextra()
1610 {
1611 if (peekword() < lineend())
1612 cueabort(_("Extra text '%s'"), peekword());
1613 }
1614
1615 /* VARARGS2 */
1616 #ifdef PROTOTYPES
1617 LOCAL void
statewarn(state_t * sp,const char * fmt,...)1618 statewarn(state_t *sp, const char *fmt, ...)
1619 #else
1620 LOCAL void
1621 statewarn(sp, fmt, va_alist)
1622 state_t *sp;
1623 char *fmt;
1624 va_dcl
1625 #endif
1626 {
1627 va_list args;
1628
1629 #ifdef PROTOTYPES
1630 va_start(args, fmt);
1631 #else
1632 va_start(args);
1633 #endif
1634 errmsgno(EX_BAD, _("%r. Current state is '%s'.\n"),
1635 fmt, args, state_name(sp->state));
1636 va_end(args);
1637 }
1638
1639 #ifdef __needed__
1640 /* VARARGS1 */
1641 #ifdef PROTOTYPES
1642 LOCAL void
cuewarn(const char * fmt,...)1643 cuewarn(const char *fmt, ...)
1644 #else
1645 LOCAL void
1646 cuewarn(fmt, va_alist)
1647 char *fmt;
1648 va_dcl
1649 #endif
1650 {
1651 va_list args;
1652
1653 #ifdef PROTOTYPES
1654 va_start(args, fmt);
1655 #else
1656 va_start(args);
1657 #endif
1658 errmsgno(EX_BAD, _("%r on line %d col %d in '%s'.\n"),
1659 fmt, args, lineno, linep - linebuf, fname);
1660 va_end(args);
1661 }
1662 #endif
1663
1664 /* VARARGS1 */
1665 #ifdef PROTOTYPES
1666 LOCAL void
cueabort(const char * fmt,...)1667 cueabort(const char *fmt, ...)
1668 #else
1669 LOCAL void
1670 cueabort(fmt, va_alist)
1671 char *fmt;
1672 va_dcl
1673 #endif
1674 {
1675 va_list args;
1676
1677 #ifdef PROTOTYPES
1678 va_start(args, fmt);
1679 #else
1680 va_start(args);
1681 #endif
1682 #ifdef PARSE_DEBUG
1683 errmsgno(EX_BAD, _("%r on line %d col %d in '%s'.\n"),
1684 #else
1685 comerrno(EX_BAD, _("%r on line %d col %d in '%s'.\n"),
1686 #endif
1687 fmt, args, lineno, linep - linebuf, fname);
1688 va_end(args);
1689 }
1690
1691 /* VARARGS1 */
1692 #ifdef PROTOTYPES
1693 LOCAL void
extabort(const char * fmt,...)1694 extabort(const char *fmt, ...)
1695 #else
1696 LOCAL void
1697 extabort(fmt, va_alist)
1698 char *fmt;
1699 va_dcl
1700 #endif
1701 {
1702 va_list args;
1703
1704 #ifdef PROTOTYPES
1705 va_start(args, fmt);
1706 #else
1707 va_start(args);
1708 #endif
1709 errmsgno(EX_BAD, _("Unsupported by CDRWIN: %r on line %d col %d in '%s'.\n"),
1710 fmt, args, lineno, linep - linebuf, fname);
1711 va_end(args);
1712 errmsgno(EX_BAD, _("Add 'REM CDRTOOLS' to enable cdrtools specific CUE extensions.\n"));
1713 comexit(EX_BAD);
1714 }
1715