/*-------------- Telecommunications & Signal Processing Lab ---------------
                             McGill University

Routine:
  int AFgetSPrec (const char name[], int type, void *data, int erropt,
                  const char head[], int N)

Purpose:
  Find a named record in a NIST SPHERE audio file header

Description:
  This routine searches through records in the header of an NIST SPHERE audio
  file looking for a record with a given name field.  The data value for that
  record is returned.  The data value is an integer value, a double value or a
  string.  For strings, the returned string is null terminated.  This routine
  should only be used for retrieving strings which are known not to contain
  imbedded null characters or imbedded newline characters.  Except for these
  limitations, this routine returns values from correctly formed records.  It
  does not attempt to verify full syntactic correctness of records.

Parameters:
  <-  int AFgetSPrec
      Returned error status, 0 for no error, 1 for no keyword match, 2 for
      decoding error
   -> const char name[]
      Record name to be matched
   -> int type
      Data type, 0 for integer, 1 for double, 2 for string
  <-  void *data
      Pointer to the where the data is to be written.  For integer data, this
      should be a pointer to a long int value.  For double data, data, this
      should be a pointer to a double value.  For strings, this should be a
      pointer to a character string with room for 81 characters (80 plus a
      terminating null).  The data is not written to if an error is detected.
   -> int erropt
      Error option flag.  The parameter erropt controls how this routine reacts
      if a matching name is not found.
      erropt - 0  No match: no error message
               1  No match: error message
   -> const char head[]
      Character string (N characters) with the header records
   -> int N
      Length of the header string

Author / revision:
  P. Kabal  Copyright (C) 1997
  $Revision: 1.20 $  $Date: 1997/10/14 14:06:49 $

-------------------------------------------------------------------------*/

static char rcsid[] = "$Id: AFgetSPrec.c 1.20 1997/10/14 libtsp-v3r0 $";

#include <assert.h>

#include <libtsp.h>
#include <libtsp/AFheader.h>
#include <libtsp/Xstdio.h>
#include <libtsp/Xstring.h>
#include <libtsp/AFmsg.h>

#define MAXRECORD	1024
#define MAXSTRING	80

#define T_INTEGER	0
#define T_REAL		1
#define T_STRING	2

#define ERR_NOMSG	0
#define ERR_MSG		1

#define RET_NOMATCH	1
#define RET_BADVALUE	2

static char *
AF_sepRecSP p_((const char name[], const char head[], int N));


int
AFgetSPrec (name, type, data, erropt, head, N)

     const char name[];
     int type;
     void *data;
     int erropt;
     const char head[];
     int N;

{
  char *p;
  int d_len, Ncs;
  char dataf[MAXRECORD+1];
  char *valuef;
  long int Iv;
  double Dv;

/* Search for a matching record */
  p = AF_sepRecSP (name, head, N);
  if (p == NULL) {
    if (erropt == ERR_MSG)
      UTwarn (AFMF_SP_NoMatch, "AFgetSPrec -", name);
    return RET_NOMATCH;
  }

/* Copy the type and value fields to temporary storage */
  d_len = (char *) memchr (p, '\n', N - (p - head)) - p;
  assert (d_len <= MAXRECORD);
  memcpy (dataf, p, d_len);
  dataf[d_len] = '\0';

/* Find the end of the type field */
  p = strchr (dataf, ' ');
  if (p != NULL) {
    *p = '\0';
    valuef = p + 1;
  }
  else
    valuef = &dataf[d_len];

/* Decode the type field */
  if (type == T_INTEGER) {
    if (strcmp (dataf, "-i") == 0 && sscanf (valuef, "%ld", &Iv) == 1) {
      *((long int *) data) = Iv;
      return 0;
    }
  }
  else if (type == T_REAL) {
    if (strcmp (dataf, "-r") == 0 && sscanf (valuef, "%lg", &Dv) == 1) {
      *((double *) data) = Dv;
      return 0;
    }
  }
  else if (type == T_STRING) {
    if (strncmp (dataf, "-s", 2) == 0
	&& sscanf (&dataf[2], "%d", &Ncs) == 1
	&& Ncs > 0 && Ncs <= MAXSTRING) {
      STcopyNMax (valuef, (char *) data, Ncs, MAXSTRING);
      return 0;
    }
  }

/* Error messages */
  UTwarn (AFMF_SP_BadField, "AFgetSPrec -", name);
  return RET_BADVALUE;
}

/*
  This routine searches through records in the header of an NIST SPHERE audio
  file, looking for a record with a given name field.  For the purpose of this
  routine, a name is the leading part of a record, separated from the type and
  value fields by a blank.  This routine returns a pointer to the beginning of
  the type field.

  In the syntax for NIST SPHERE headers, a newline character marks the end of a
  record.  But, the header syntax also allows for any character, including a
  newline character, to appear within a string value.  To avoid parsing each
  record to find the end of record, this routine assumes all newline characters
  terminate records.  Any newline character imbedded in a string value must not
  be followed by a sequence of characters which would be mistaken for the name
  field at the beginning of a record.
*/

static char *
AF_sepRecSP (name, head, N)

     const char name[];
     const char head[];
     int N;

{
  const char *pst;
  const char *h_end;
  const char *r_term;
  int lenn;

  h_end = &head[N-1];
  pst = head;
  lenn = strlen (name);
  while (pst <= h_end) {

    /* Find the record terminator */
    r_term = (char *) memchr (pst, '\n', h_end - pst + 1);
    if (r_term == NULL)
      break;

    /* Check for a name match */
    if (r_term - pst >= lenn + 1 && memcmp (pst, name, lenn) == 0
	&& pst[lenn] == ' ') {
      return ((char *) (pst + lenn + 1));
    }
    pst = r_term + 1;
  }

/* No match to the name */
  return NULL;
}
