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