# include <ohana.h>
# include <gfitsio.h>

int gfits_scan (Header *header, char *field, char *mode, int N,...) {

  int status;
  va_list argp;
  
  va_start (argp, N);
  status = gfits_vscan (header, field, mode, N, argp);
  va_end (argp);
  return (status);
}
  
int gfits_vscan (Header *header, char *field, char *mode, int N, va_list argp) {

  char *p, *q, *s, tmp[81];
  int Nchar, status;
  double value;
  
  /* find the correct line with field */
  p = gfits_header_field (header, field, N);
  if (p == NULL) {
    status = gfits_vscan_hierarch (header, field, mode, N, argp);
    return (status);
  }

  /* non-data entry (COMMENT, HISTORY) */
  if (!strcmp (mode, "%S")) {
    strncpy (va_arg (argp, char *), p + 8, FT_HISTORY_LENGTH);
    return (TRUE);
  }

  /* all others require '=' in column 8 */
  if (p[8] != '=') return (FALSE);

  /* comment from data line */
  if (!strcmp (mode, "%C")) {
    q = gfits_keyword_end (p) + 3;
    q = MIN (p + 80, q);
    bzero (tmp, 81);
    Nchar = MIN (80, p + 80 - q);
    memcpy (tmp, q, Nchar);
    stripwhite (tmp);
    strcpy (va_arg (argp, char *), tmp);
    return (TRUE);
  }

  /* extract data into char array (exclude containing ' chars) */
  if (!strcmp (mode, "%s")) {
    s = gfits_keyword_start (p); /* points at first char (not ') */
    q = gfits_keyword_end (p); /* points at following space or ' */

    Nchar = MAX (0, (q - s));
    bzero (tmp, 81);
    memcpy (tmp, s, Nchar);
    stripwhite (tmp);
    strcpy (va_arg (argp, char *), tmp);
    return (TRUE);
  }
  
  /* boolean data, requires int target */
  if (!strcmp (mode, "%t")) {
    s = gfits_keyword_start (p);
    if (*s == 'T') {
      *va_arg (argp, int *) = TRUE;
      return (TRUE);
    }
    if (*s == 'F') {
      *va_arg (argp, int *) = FALSE;   
      return (TRUE);
    }
  }

  /* remaining options are numerical data */
  /* need to interpret 1.0d5 as 1.0e5 */
  s = gfits_keyword_start (p); /* points at first char (not ') */
  q = gfits_keyword_end (p); /* points at following space or ' */
  value = strtod (s, &q);
  if ((*q == 'd') || (*q == 'D')) 
    value *= pow (10.0, atof (q + 1));

  if (!strcmp (mode, "%d"))  { *va_arg (argp, int *)       = value; return (TRUE); }
  if (!strcmp (mode, "%u"))  { *va_arg (argp, unsigned *)  = value; return (TRUE); }
  if (!strcmp (mode, "%ld")) { *va_arg (argp, long *)      = value; return (TRUE); }
  if (!strcmp (mode, "%hd")) { *va_arg (argp, short *)     = value; return (TRUE); }
  if (!strcmp (mode, "%f"))  { *va_arg (argp, float *)     = value; return (TRUE); }
  if (!strcmp (mode, "%lf")) { *va_arg (argp, double *)    = value; return (TRUE); }

  /* no valid mode found */
  return (FALSE);
}

# define HIERARCH_LENGTH 71
int gfits_vscan_hierarch (Header *header, char *field, char *mode, int N, va_list argp) {

  char *p, *q, *s, tmp[81];
  int Nchar, Nfield;
  double value;
  
  /* find the correct line with field */
  p = gfits_header_hierarch_field (header, field, N);
  if (p == NULL) return (FALSE);

  /* non-data entries (COMMENT, HISTORY) are not allowed */
  if (!strcmp (mode, "%S")) {
    return (FALSE);
  }

  /* all others require '=' in column p + 1 + strlen(field) */
  Nfield = strlen (field);
  if (p[Nfield + 1] != '=') return (FALSE);

  /* comment from data line */
  if (!strcmp (mode, "%C")) {
    q = gfits_hierarch_keyword_end (p, field);
    if (!q) return (FALSE);
    q += 3;
    q = MIN (p + HIERARCH_LENGTH, q);
    bzero (tmp, 81);
    Nchar = MIN (HIERARCH_LENGTH, p + HIERARCH_LENGTH - q);
    memcpy (tmp, q, Nchar);
    stripwhite (tmp);
    strcpy (va_arg (argp, char *), tmp);
    return (TRUE);
  }

  /* extract data into char array (exclude containing ' chars) */
  if (!strcmp (mode, "%s")) {
    s = gfits_hierarch_keyword_start (p, field); /* points at first char (not ') */
    q = gfits_hierarch_keyword_end (p, field); /* points at following space or ' */

    Nchar = MIN (HIERARCH_LENGTH, MAX (0, (q - s)));
    bzero (tmp, 81);
    memcpy (tmp, s, Nchar);
    stripwhite (tmp);
    strcpy (va_arg (argp, char *), tmp);
    return (TRUE);
  }
  
  /* boolean data, requires int target */
  if (!strcmp (mode, "%t")) {
    s = gfits_hierarch_keyword_start (p, field);
    if (*s == 'T') {
      *va_arg (argp, int *) = TRUE;
      return (TRUE);
    }
    if (*s == 'F') {
      *va_arg (argp, int *) = FALSE;   
      return (TRUE);
    }
  }

  /* remaining options are numerical data */
  /* need to interpret 1.0d5 as 1.0e5 */
  s = gfits_hierarch_keyword_start (p, field); /* points at first char (not ') */
  q = gfits_hierarch_keyword_end (p, field); /* points at following space or ' */
  value = strtod (s, &q);
  if ((*q == 'd') || (*q == 'D')) 
    value *= pow (10.0, atof (q + 1));

  if (!strcmp (mode, "%d"))  { *va_arg (argp, int *)       = value; return (TRUE); }
  if (!strcmp (mode, "%u"))  { *va_arg (argp, unsigned *)  = value; return (TRUE); }
  if (!strcmp (mode, "%ld")) { *va_arg (argp, long *)      = value; return (TRUE); }
  if (!strcmp (mode, "%hd")) { *va_arg (argp, short *)     = value; return (TRUE); }
  if (!strcmp (mode, "%f"))  { *va_arg (argp, float *)     = value; return (TRUE); }
  if (!strcmp (mode, "%lf")) { *va_arg (argp, double *)    = value; return (TRUE); }

  /* no valid mode found */
  return (FALSE);
}

/* if the variable argument stuff breaks on another system, look 
at F_modify.c as it has the old code */
