Пример #1
0
int
main(int argc, const char *argv[])
{
    const char *cue_filename[] = {
	"/tmp/foo.bar",
	"foo.bar"
    };
    const char *expect[] = {
	"/tmp/baz",
	"./baz"
    };

  int rc=0;
  int i;

  for (i=0; i<2; i++) {
      char *dirname = cdio_dirname(cue_filename[i]);
      char *dest = cdio_abspath(dirname, "baz");
      if (0 != strcmp(expect[i], dest)) {
	  fprintf(stderr, 
		  "Incorrect: expecting %s, got %s.\n",
		  expect[i], dest);
	  rc=i+1;
      }
      free(dirname);
      free(dest);
  }
  exit(rc);
}
Пример #2
0
int main(int argc, char **argv)
{
  const char *dest;
  const char *dirname;
  if (argc != 3) {
    fprintf(stderr, "Usage: %s FILE REPLACE_BASENAME\n", argv[0]);
    fprintf(stderr,
     "       Make PATH absolute\n");
    exit(1);
  }

  dirname = cdio_dirname(argv[1]);
  dest = cdio_abspath (dirname, argv[2]);
  printf("%s -> %s\n", argv[1], dest);
  exit(0);
}
Пример #3
0
static bool
parse_tocfile (_img_private_t *cd, const char *psz_cue_name)
{
  /* The below declarations may be common in other image-parse routines. */
  FILE        *fp;
  char         psz_line[MAXLINE];   /* text of current line read in file fp. */
  unsigned int i_line=0;            /* line number in file of psz_line. */
  int          i = -1;              /* Position in tocent. Same as
				       cd->gen.i_tracks - 1 */
  char *psz_keyword, *psz_field, *psz_cue_name_dup;
  cdio_log_level_t log_level = (cd) ? CDIO_LOG_WARN : CDIO_LOG_INFO ;
  cdtext_field_t cdtext_key;

  /* The below declaration(s) may be unique to this image-parse routine. */
  unsigned int i_cdtext_nest = 0;

  if (NULL == psz_cue_name)
    return false;

  psz_cue_name_dup = _cdio_strdup_fixpath(psz_cue_name);
  if (NULL == psz_cue_name_dup)
    return false;

  fp = CDIO_FOPEN (psz_cue_name_dup, "r");
  cdio_free(psz_cue_name_dup);
  if (fp == NULL) {
    cdio_log(log_level, "error opening %s for reading: %s",
	     psz_cue_name, strerror(errno));
    return false;
  }

  if (cd) {
    cd->gen.b_cdtext_error = false;
  }

  while (fgets(psz_line, MAXLINE, fp)) {

    i_line++;

    /* strip comment from line */
    /* todo: // in quoted strings? */
    /* //comment */
    if ((psz_field = strstr (psz_line, "//")))
      *psz_field = '\0';

    if ((psz_keyword = strtok (psz_line, " \t\n\r"))) {
      /* CATALOG "ddddddddddddd" */
      if (0 == strcmp ("CATALOG", psz_keyword)) {
	if (-1 == i) {
	  if (NULL != (psz_field = strtok (NULL, "\"\t\n\r"))) {
	    if (13 != strlen(psz_field)) {
	      cdio_log(log_level,
		       "%s line %d after word CATALOG:",
		       psz_cue_name, i_line);
	      cdio_log(log_level,
		       "Token %s has length %ld. Should be 13 digits.",
		       psz_field, (long int) strlen(psz_field));

	      goto err_exit;
	    } else {
	      /* Check that we have all digits*/
	      unsigned int j;
	      for (j=0; j<13; j++) {
		if (!isdigit((unsigned char) psz_field[j])) {
		    cdio_log(log_level,
			     "%s line %d after word CATALOG:",
			     psz_cue_name, i_line);
		    cdio_log(log_level,
			     "Character \"%c\" at postition %i of token \"%s\""
			     " is not all digits.",
			     psz_field[j], j+1, psz_field);
		    goto err_exit;
		}
	      }
	      if (NULL != cd) cd->psz_mcn = strdup (psz_field);
	    }
	  } else {
	    cdio_log(log_level,
		     "%s line %d after word CATALOG:",
		     psz_cue_name, i_line);
	    cdio_log(log_level, "Expecting 13 digits; nothing seen.");
	    goto err_exit;
	  }
	} else {
	  goto err_exit;
	}

	/* CD_DA | CD_ROM | CD_ROM_XA */
      } else if (0 == strcmp ("CD_DA", psz_keyword)) {
	if (-1 == i) {
	  if (NULL != cd)
	    cd->disc_mode = CDIO_DISC_MODE_CD_DA;
	} else {
	  goto not_in_global_section;
	}
      } else if (0 == strcmp ("CD_ROM", psz_keyword)) {
	if (-1 == i) {
	  if (NULL != cd)
	    cd->disc_mode = CDIO_DISC_MODE_CD_DATA;
	} else {
	  goto not_in_global_section;
	}

      } else if (0 == strcmp ("CD_ROM_XA", psz_keyword)) {
	if (-1 == i) {
	  if (NULL != cd)
	    cd->disc_mode = CDIO_DISC_MODE_CD_XA;
	} else {
	  goto not_in_global_section;
	}

	/* TRACK <track-mode> [<sub-channel-mode>] */
      } else if (0 == strcmp ("TRACK", psz_keyword)) {
	i++;
	if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) {
	  if (0 == strcmp ("AUDIO", psz_field)) {
	    if (NULL != cd) {
	      cd->tocent[i].track_format = TRACK_FORMAT_AUDIO;
	      cd->tocent[i].blocksize    = CDIO_CD_FRAMESIZE_RAW;
	      cd->tocent[i].datasize     = CDIO_CD_FRAMESIZE_RAW;
	      cd->tocent[i].datastart    = 0;
	      cd->tocent[i].endsize      = 0;
	      switch(cd->disc_mode) {
	      case CDIO_DISC_MODE_NO_INFO:
		cd->disc_mode = CDIO_DISC_MODE_CD_DA;
		break;
	      case CDIO_DISC_MODE_CD_DA:
	      case CDIO_DISC_MODE_CD_MIXED:
	      case CDIO_DISC_MODE_ERROR:
		/* Disc type stays the same. */
		break;
	      case CDIO_DISC_MODE_CD_DATA:
	      case CDIO_DISC_MODE_CD_XA:
		cd->disc_mode = CDIO_DISC_MODE_CD_MIXED;
		break;
	      default:
		cd->disc_mode = CDIO_DISC_MODE_ERROR;
	      }

	    }
	  } else if (0 == strcmp ("MODE1", psz_field)) {
	    if (NULL != cd) {
	      cd->tocent[i].track_format = TRACK_FORMAT_DATA;
	      cd->tocent[i].blocksize    = CDIO_CD_FRAMESIZE_RAW;
	      cd->tocent[i].datastart    = CDIO_CD_SYNC_SIZE
		+ CDIO_CD_HEADER_SIZE;
	      cd->tocent[i].datasize     = CDIO_CD_FRAMESIZE;
	      cd->tocent[i].endsize      = CDIO_CD_EDC_SIZE
		+ CDIO_CD_M1F1_ZERO_SIZE + CDIO_CD_ECC_SIZE;
	      switch(cd->disc_mode) {
	      case CDIO_DISC_MODE_NO_INFO:
		cd->disc_mode = CDIO_DISC_MODE_CD_DATA;
		break;
	      case CDIO_DISC_MODE_CD_DATA:
	      case CDIO_DISC_MODE_CD_MIXED:
	      case CDIO_DISC_MODE_ERROR:
		/* Disc type stays the same. */
		break;
	      case CDIO_DISC_MODE_CD_DA:
	      case CDIO_DISC_MODE_CD_XA:
		cd->disc_mode = CDIO_DISC_MODE_CD_MIXED;
		break;
	      default:
		cd->disc_mode = CDIO_DISC_MODE_ERROR;
	      }
	    }
	  } else if (0 == strcmp ("MODE1_RAW", psz_field)) {
	    if (NULL != cd) {
	      cd->tocent[i].track_format = TRACK_FORMAT_DATA;
	      cd->tocent[i].blocksize = CDIO_CD_FRAMESIZE_RAW;
	      cd->tocent[i].datastart = CDIO_CD_SYNC_SIZE
		+ CDIO_CD_HEADER_SIZE;
	      cd->tocent[i].datasize  = CDIO_CD_FRAMESIZE;
	      cd->tocent[i].endsize   = CDIO_CD_EDC_SIZE
		+ CDIO_CD_M1F1_ZERO_SIZE + CDIO_CD_ECC_SIZE;
	      switch(cd->disc_mode) {
	      case CDIO_DISC_MODE_NO_INFO:
		cd->disc_mode = CDIO_DISC_MODE_CD_DATA;
		break;
	      case CDIO_DISC_MODE_CD_DATA:
	      case CDIO_DISC_MODE_CD_MIXED:
	      case CDIO_DISC_MODE_ERROR:
		/* Disc type stays the same. */
		break;
	      case CDIO_DISC_MODE_CD_DA:
	      case CDIO_DISC_MODE_CD_XA:
		cd->disc_mode = CDIO_DISC_MODE_CD_MIXED;
		break;
	      default:
		cd->disc_mode = CDIO_DISC_MODE_ERROR;
	      }
	    }
	  } else if (0 == strcmp ("MODE2", psz_field)) {
	    if (NULL != cd) {
	      cd->tocent[i].track_format = TRACK_FORMAT_XA;
	      cd->tocent[i].datastart = CDIO_CD_SYNC_SIZE
		+ CDIO_CD_HEADER_SIZE;
	      cd->tocent[i].datasize = M2RAW_SECTOR_SIZE;
	      cd->tocent[i].endsize   = 0;
	      switch(cd->disc_mode) {
	      case CDIO_DISC_MODE_NO_INFO:
		cd->disc_mode = CDIO_DISC_MODE_CD_XA;
		break;
	      case CDIO_DISC_MODE_CD_XA:
	      case CDIO_DISC_MODE_CD_MIXED:
	      case CDIO_DISC_MODE_ERROR:
		/* Disc type stays the same. */
		break;
	      case CDIO_DISC_MODE_CD_DA:
	      case CDIO_DISC_MODE_CD_DATA:
		cd->disc_mode = CDIO_DISC_MODE_CD_MIXED;
		break;
	      default:
		cd->disc_mode = CDIO_DISC_MODE_ERROR;
	      }
	    }
	  } else if (0 == strcmp ("MODE2_FORM1", psz_field)) {
	    if (NULL != cd) {
	      cd->tocent[i].track_format = TRACK_FORMAT_XA;
	      cd->tocent[i].datastart = CDIO_CD_SYNC_SIZE
		+ CDIO_CD_HEADER_SIZE;
	      cd->tocent[i].datasize  = CDIO_CD_FRAMESIZE_RAW;
	      cd->tocent[i].endsize   = 0;
	      switch(cd->disc_mode) {
	      case CDIO_DISC_MODE_NO_INFO:
		cd->disc_mode = CDIO_DISC_MODE_CD_XA;
		break;
	      case CDIO_DISC_MODE_CD_XA:
	      case CDIO_DISC_MODE_CD_MIXED:
	      case CDIO_DISC_MODE_ERROR:
		/* Disc type stays the same. */
		break;
	      case CDIO_DISC_MODE_CD_DA:
	      case CDIO_DISC_MODE_CD_DATA:
		cd->disc_mode = CDIO_DISC_MODE_CD_MIXED;
		break;
	      default:
		cd->disc_mode = CDIO_DISC_MODE_ERROR;
	      }
	    }
	  } else if (0 == strcmp ("MODE2_FORM2", psz_field)) {
	    if (NULL != cd) {
	      cd->tocent[i].track_format = TRACK_FORMAT_XA;
	      cd->tocent[i].datastart    = CDIO_CD_SYNC_SIZE
		+ CDIO_CD_HEADER_SIZE + CDIO_CD_SUBHEADER_SIZE;
	      cd->tocent[i].datasize     = CDIO_CD_FRAMESIZE;
	      cd->tocent[i].endsize      = CDIO_CD_SYNC_SIZE
		+ CDIO_CD_ECC_SIZE;
	      switch(cd->disc_mode) {
	      case CDIO_DISC_MODE_NO_INFO:
		cd->disc_mode = CDIO_DISC_MODE_CD_XA;
		break;
	      case CDIO_DISC_MODE_CD_XA:
	      case CDIO_DISC_MODE_CD_MIXED:
	      case CDIO_DISC_MODE_ERROR:
		/* Disc type stays the same. */
		break;
	      case CDIO_DISC_MODE_CD_DA:
	      case CDIO_DISC_MODE_CD_DATA:
		cd->disc_mode = CDIO_DISC_MODE_CD_MIXED;
		break;
	      default:
		cd->disc_mode = CDIO_DISC_MODE_ERROR;
	      }
	    }
	  } else if (0 == strcmp ("MODE2_FORM_MIX", psz_field)) {
	    if (NULL != cd) {
	      cd->tocent[i].track_format = TRACK_FORMAT_XA;
	      cd->tocent[i].datasize     = M2RAW_SECTOR_SIZE;
	      cd->tocent[i].blocksize    = CDIO_CD_FRAMESIZE_RAW;
	      cd->tocent[i].datastart    = CDIO_CD_SYNC_SIZE +
		CDIO_CD_HEADER_SIZE + CDIO_CD_SUBHEADER_SIZE;
	      cd->tocent[i].track_green  = true;
	      cd->tocent[i].endsize      = 0;
	      switch(cd->disc_mode) {
	      case CDIO_DISC_MODE_NO_INFO:
		cd->disc_mode = CDIO_DISC_MODE_CD_XA;
		break;
	      case CDIO_DISC_MODE_CD_XA:
	      case CDIO_DISC_MODE_CD_MIXED:
	      case CDIO_DISC_MODE_ERROR:
		/* Disc type stays the same. */
		break;
	      case CDIO_DISC_MODE_CD_DA:
	      case CDIO_DISC_MODE_CD_DATA:
		cd->disc_mode = CDIO_DISC_MODE_CD_MIXED;
		break;
	      default:
		cd->disc_mode = CDIO_DISC_MODE_ERROR;
	      }
	    }
	  } else if (0 == strcmp ("MODE2_RAW", psz_field)) {
	    if (NULL != cd) {
	      cd->tocent[i].track_format = TRACK_FORMAT_XA;
	      cd->tocent[i].blocksize    = CDIO_CD_FRAMESIZE_RAW;
	      cd->tocent[i].datastart    = CDIO_CD_SYNC_SIZE +
		CDIO_CD_HEADER_SIZE + CDIO_CD_SUBHEADER_SIZE;
	      cd->tocent[i].datasize     = CDIO_CD_FRAMESIZE;
	      cd->tocent[i].track_green  = true;
	      cd->tocent[i].endsize      = 0;
	      switch(cd->disc_mode) {
	      case CDIO_DISC_MODE_NO_INFO:
		cd->disc_mode = CDIO_DISC_MODE_CD_XA;
		break;
	      case CDIO_DISC_MODE_CD_XA:
	      case CDIO_DISC_MODE_CD_MIXED:
	      case CDIO_DISC_MODE_ERROR:
		/* Disc type stays the same. */
		break;
	      case CDIO_DISC_MODE_CD_DA:
	      case CDIO_DISC_MODE_CD_DATA:
		cd->disc_mode = CDIO_DISC_MODE_CD_MIXED;
		break;
	      default:
		cd->disc_mode = CDIO_DISC_MODE_ERROR;
	      }
	    }
	  } else {
	    cdio_log(log_level, "%s line %d after TRACK:",
		     psz_cue_name, i_line);
	    cdio_log(log_level, "'%s' not a valid mode.", psz_field);
	    goto err_exit;
	  }
	}
	if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) {
	  /* \todo: set sub-channel-mode */
#ifdef TODO
	  if (0 == strcmp ("RW", psz_field))
	    ;
	  else if (0 == strcmp ("RW_RAW", psz_field))
	    ;
#endif
	}
	if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) {
	  goto format_error;
	}

	/* track flags */
	/* [NO] COPY | [NO] PRE_EMPHASIS */
      } else if (0 == strcmp ("NO", psz_keyword)) {
	if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) {
	  if (0 == strcmp ("COPY", psz_field)) {
	    if (NULL != cd)
	      cd->tocent[i].flags &= ~CDIO_TRACK_FLAG_COPY_PERMITTED;

	  } else if (0 == strcmp ("PRE_EMPHASIS", psz_field))
	    if (NULL != cd) {
	      cd->tocent[i].flags &= ~CDIO_TRACK_FLAG_PRE_EMPHASIS;
	    }
	} else {
	  goto format_error;
	}
	if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) {
	  goto format_error;
	}
      } else if (0 == strcmp ("COPY", psz_keyword)) {
	if (NULL != cd && i >= 0)
	  cd->tocent[i].flags |= CDIO_TRACK_FLAG_COPY_PERMITTED;
      } else if (0 == strcmp ("PRE_EMPHASIS", psz_keyword)) {
	if (NULL != cd && i >= 0)
	  cd->tocent[i].flags |= CDIO_TRACK_FLAG_PRE_EMPHASIS;
	/* TWO_CHANNEL_AUDIO */
      } else if (0 == strcmp ("TWO_CHANNEL_AUDIO", psz_keyword)) {
	if (NULL != cd && i >= 0)
	  cd->tocent[i].flags &= ~CDIO_TRACK_FLAG_FOUR_CHANNEL_AUDIO;
	/* FOUR_CHANNEL_AUDIO */
      } else if (0 == strcmp ("FOUR_CHANNEL_AUDIO", psz_keyword)) {
	if (NULL != cd && i >= 0)
	  cd->tocent[i].flags |= CDIO_TRACK_FLAG_FOUR_CHANNEL_AUDIO;

	/* ISRC "CCOOOYYSSSSS" */
      } else if (0 == strcmp ("ISRC", psz_keyword)) {
	if (NULL != (psz_field = strtok (NULL, "\"\t\n\r"))) {
	  if (NULL != cd)
	    cd->tocent[i].isrc = strdup(psz_field);
	} else {
	  goto format_error;
	}

	/* SILENCE <length> */
      } else if (0 == strcmp ("SILENCE", psz_keyword)) {
	  if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) {
	      if (NULL != cd)
		  cd->tocent[i].silence = cdio_mmssff_to_lba (psz_field);
	  } else {
	      goto format_error;
	  }
	  cdio_log(log_level, "%s line %d: SILENCE not fully implimented",
		   psz_cue_name, i_line);

	/* ZERO <length> */
      } else if (0 == strcmp ("ZERO", psz_keyword)) {
	UNIMPLIMENTED_MSG;

	/* [FILE|AUDIOFILE] "<filename>" <start-msf> [<length-msf>] */
      } else if (0 == strcmp ("FILE", psz_keyword)
		 || 0 == strcmp ("AUDIOFILE", psz_keyword)) {
	if (0 <= i) {
	  if (NULL != (psz_field = strtok (NULL, "\"\t\n\r"))) {
	    /* Handle "<filename>" */
	    if (cd) {
	      char *psz_dirname = cdio_dirname(psz_cue_name);
	      char *psz_filename = cdio_abspath(psz_dirname, psz_field);
	      cd->tocent[i].filename = strdup (psz_filename);
	      free(psz_filename);
	      free(psz_dirname);
	      /* To do: do something about reusing existing files. */
	      if (!(cd->tocent[i].data_source = cdio_stdio_new (psz_field))) {
		cdio_log (log_level,
			  "%s line %d: can't open file `%s' for reading",
			   psz_cue_name, i_line, psz_field);
		goto err_exit;
	      }
	    } else {
	      CdioDataSource_t *s = cdio_stdio_new (psz_field);
	      if (!s) {
		cdio_log (log_level,
			  "%s line %d: can't open file `%s' for reading",
			  psz_cue_name, i_line, psz_field);
		goto err_exit;
	      }
	      cdio_stdio_destroy (s);
	    }
	  }

	  if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) {
	    /* Handle <start-msf> */
	    lba_t i_start_lba =
	      cdio_lsn_to_lba(cdio_mmssff_to_lba (psz_field));
	    if (CDIO_INVALID_LBA == i_start_lba) {
	      cdio_log(log_level, "%s line %d: invalid MSF string %s",
		       psz_cue_name, i_line, psz_field);
	      goto err_exit;
	    }

	    if (NULL != cd) {
	      cd->tocent[i].start_lba = i_start_lba;
	      cdio_lba_to_msf(i_start_lba, &(cd->tocent[i].start_msf));
	    }
	  }
	  if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) {
	    /* Handle <length-msf> */
	    lba_t lba = cdio_mmssff_to_lba (psz_field);
	    if (CDIO_INVALID_LBA == lba) {
	      cdio_log(log_level, "%s line %d: invalid MSF string %s",
		       psz_cue_name, i_line, psz_field);
	      goto err_exit;
	    }
	    if (cd) {
	      off_t i_size = cdio_stream_stat(cd->tocent[i].data_source);
	      if (lba) {
		if ( (lba * cd->tocent[i].datasize) > i_size) {
		  cdio_log(log_level,
			   "%s line %d: MSF length %s exceeds end of file",
			   psz_cue_name, i_line, psz_field);
		  goto err_exit;
		}
	      } else {
		lba = (lba_t) (i_size / cd->tocent[i].blocksize);
	      }
	      cd->tocent[i].sec_count = lba;
	    }
	  }
	  if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) {
	    goto format_error;
	  }
	} else {
	  goto not_in_global_section;
	}

	/* DATAFILE "<filename>" #byte-offset <start-msf> */
      } else if (0 == strcmp ("DATAFILE", psz_keyword)) {
	if (0 <= i) {
	  if (NULL != (psz_field = strtok (NULL, "\"\t\n\r"))) {
	    /* Handle <filename> */
	    char *psz_dirname = cdio_dirname(psz_cue_name);
	    char *psz_filename = cdio_abspath(psz_dirname, psz_field);
	    if (cd) {
	      cd->tocent[i].filename = strdup(psz_filename);
	      /* To do: do something about reusing existing files. */
	      if (!(cd->tocent[i].data_source = cdio_stdio_new (psz_field))) {
		cdio_log (log_level,
			  "%s line %d: can't open file `%s' for reading",
			  psz_cue_name, i_line, psz_field);
		free(psz_filename);
		free(psz_dirname);
		goto err_exit;
	      }
	    } else {
	      CdioDataSource_t *s = cdio_stdio_new (psz_filename);
	      if (!s) {
		cdio_log (log_level,
			  "%s line %d: can't open file `%s' for reading",
			  psz_cue_name, i_line, psz_field);
		free(psz_filename);
		free(psz_dirname);
		goto err_exit;
	      }
	      cdio_stdio_destroy (s);
	    }
	    free(psz_filename);
	    free(psz_dirname);
	  }

	  psz_field = strtok (NULL, " \t\n\r");
	  if (psz_field) {
	    /* Handle optional #byte-offset */
	    if ( psz_field[0] == '#') {
	      long int offset;
	      psz_field++;
	      errno = 0;
	      offset = strtol(psz_field, (char **)NULL, 10);
	      if ( (LONG_MIN == offset || LONG_MAX == offset)
		   && 0 != errno ) {
		cdio_log (log_level,
			  "%s line %d: can't convert `%s' to byte offset",
			  psz_cue_name, i_line, psz_field);
		goto err_exit;
	      } else {
		if (NULL != cd) {
		  cd->tocent[i].offset = offset;
		}
	      }
	      psz_field = strtok (NULL, " \t\n\r");
	    }
	  }
	  if (psz_field) {
	    /* Handle start-msf */
	    lba_t lba = cdio_mmssff_to_lba (psz_field);
	    if (CDIO_INVALID_LBA == lba) {
	      cdio_log(log_level, "%s line %d: invalid MSF string %s",
		       psz_cue_name, i_line, psz_field);
	      goto err_exit;
	    }
	    if (cd) {
	      cd->tocent[i].start_lba = lba;
	      cdio_lba_to_msf(cd->tocent[i].start_lba,
			      &(cd->tocent[i].start_msf));
	    }
	  } else {
	    /* No start-msf. */
	    if (cd) {
	      if (i) {
		uint16_t i_blocksize = cd->tocent[i-1].blocksize;
		off_t i_size      =
		  cdio_stream_stat(cd->tocent[i-1].data_source);

		  check_track_is_blocksize_multiple(cd->tocent[i-1].filename,
						    i-1, i_size, i_blocksize);
		/* Append size of previous datafile. */
		cd->tocent[i].start_lba = (lba_t) (cd->tocent[i-1].start_lba +
		  (i_size / i_blocksize));
	      }
	      cd->tocent[i].offset = 0;
	      cd->tocent[i].start_lba += CDIO_PREGAP_SECTORS;
	      cdio_lba_to_msf(cd->tocent[i].start_lba,
			      &(cd->tocent[i].start_msf));
	    }
	  }

	} else {
	  goto not_in_global_section;
	}

	/* FIFO "<fifo path>" [<length>] */
      } else if (0 == strcmp ("FIFO", psz_keyword)) {
	goto unimplimented_error;

	/* START MM:SS:FF */
      } else if (0 == strcmp ("START", psz_keyword)) {
	if (0 <= i) {
	  if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) {
	    /* todo: line is too long! */
	    if (NULL != cd) {
	      cd->tocent[i].pregap = cd->tocent[i].start_lba;
	      cd->tocent[i].start_lba += cdio_mmssff_to_lba (psz_field);
	      cdio_lba_to_msf(cd->tocent[i].start_lba,
			      &(cd->tocent[i].start_msf));
	    }
	  }

	  if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) {
	    goto format_error;
	  }
	} else {
	  goto not_in_global_section;
	}

	/* PREGAP MM:SS:FF */
      } else if (0 == strcmp ("PREGAP", psz_keyword)) {
	if (0 <= i) {
	  if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) {
	    if (NULL != cd)
	      cd->tocent[i].pregap = cdio_mmssff_to_lba (psz_field);
	  } else {
	    goto format_error;
	  }
	  if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) {
	    goto format_error;
	  }
	} else {
	  goto not_in_global_section;
	}

	  /* INDEX MM:SS:FF */
      } else if (0 == strcmp ("INDEX", psz_keyword)) {
	if (0 <= i) {
	  if (NULL != (psz_field = strtok (NULL, " \t\n\r"))) {
	    if (NULL != cd) {
#if 0
	      if (1 == cd->tocent[i].nindex) {
		cd->tocent[i].indexes[1] = cd->tocent[i].indexes[0];
		cd->tocent[i].nindex++;
	      }
	      cd->tocent[i].indexes[cd->tocent[i].nindex++] =
		cdio_mmssff_to_lba (psz_field) + cd->tocent[i].indexes[0];
#else
	      ;

#endif
	    }
	  } else {
	    goto format_error;
	  }
	  if (NULL != strtok (NULL, " \t\n\r")) {
	    goto format_error;
	  }
	}  else {
	  goto not_in_global_section;
	}

  /* CD_TEXT { ... } */
  /* todo: opening { must be on same line as CD_TEXT */
      } else if (0 == strcmp ("CD_TEXT", psz_keyword)) {
        if (NULL == (psz_field = strtok (NULL, " \t\n\r"))) {
          goto format_error;
        }
        if ( 0 == strcmp( "{", psz_field ) ) {
          i_cdtext_nest++;
        } else {
          cdio_log (log_level,
              "%s line %d: expecting '{'", psz_cue_name, i_line);
          goto err_exit;
        }

      // TODO: implement language mapping
      } else if (0 == strcmp ("LANGUAGE_MAP", psz_keyword)) {
        /* LANGUAGE d { ... } */
      } else if (0 == strcmp ("LANGUAGE", psz_keyword)) {
        /* Language number */
        if (NULL == (psz_field = strtok (NULL, " \t\n\r"))) {
          goto format_error;
        }
        if ( 0 == strcmp( "{", psz_field ) ) {
          i_cdtext_nest++;
        }
      } else if (0 == strcmp ("{", psz_keyword)) {
        i_cdtext_nest++;
      } else if (0 == strcmp ("}", psz_keyword)) {
        if (i_cdtext_nest > 0) i_cdtext_nest--;
      } else if ( CDTEXT_FIELD_INVALID !=
          (cdtext_key = cdtext_is_field (psz_keyword)) ) {
        if (NULL != cd) {
          if (NULL == cd->gen.cdtext) {
            cd->gen.cdtext = cdtext_init ();
            /* until language mapping is implemented ...*/
            cd->gen.cdtext->block[cd->gen.cdtext->block_i].language_code = CDTEXT_LANGUAGE_ENGLISH;
          }
          cdtext_set (cd->gen.cdtext, cdtext_key, (uint8_t*) strtok (NULL, "\"\t\n\r"),
              (-1 == i ? 0 : cd->gen.i_first_track + i),
              "ISO-8859-1");
        }

	/* unrecognized line */
      } else {
	cdio_log(log_level, "%s line %d: warning: unrecognized word: %s",
		 psz_cue_name, i_line, psz_keyword);
	goto err_exit;
      }
    }
  }

  if (NULL != cd) {
    cd->gen.i_tracks = i+1;
    cd->gen.toc_init = true;
  }

  fclose (fp);
  return true;

 unimplimented_error:
  UNIMPLIMENTED_MSG;
  goto err_exit;

 format_error:
  cdio_log(log_level, "%s line %d after word %s",
	   psz_cue_name, i_line, psz_keyword);
  goto err_exit;

 not_in_global_section:
  cdio_log(log_level, "%s line %d: word %s only allowed in global section",
	   psz_cue_name, i_line, psz_keyword);

 err_exit:
  fclose (fp);
  return false;
}