/*===========================================================================
  Copyright (C) 1988-2009 European Southern Observatory (ESO)
 
  This program is free software; you can redistribute it and/or 
  modify it under the terms of the GNU General Public License as 
  published by the Free Software Foundation; either version 2 of 
  the License, or (at your option) any later version.
 
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
 
  You should have received a copy of the GNU General Public 
  License along with this program; if not, write to the Free 
  Software Foundation, Inc., 675 Massachusetss Ave, Cambridge, 
  MA 02139, USA.
 
  Corresponding concerning ESO-MIDAS should be addressed as follows:
	Internet e-mail: midas@eso.org
	Postal address: European Southern Observatory
			Data Management Division 
			Karl-Schwarzschild-Strasse 2
			D 85748 Garching bei Muenchen 
			GERMANY
===========================================================================*/

/*+++++++++ 
.MODULE    traf.c
.AUTHOR    Francois Ochsenbein [ESO]
.LANGUAGE  C
.CATEGORY  Conversion from character to double.

.COMMENTS

.VERSION   1.0	20-Oct-1988: Creation

 090831		last modif
-----------------------------------------------*/
 
#include <midas_def.h>
#include <tra.h>
#include <atype.h>

extern int tr_error();



#define issign(c)		((c == '+') || (c == '-'))
#define FINISH			goto FIN
#define GobbleSpaces(s,l)	s += oscspan((unsigned char *)s, l, _SPACE_, main_ascii)

MID_EXTERN struct trerr_s	*trerror;

MID_STATIC char *stopped;		/* To communicate the stopping char */

/*===========================================================================*/
static int traf(str, len, value)
/*++++++
.PURPOSE Converts a string to a floating point.
	Input is assumed to be in decimal.
.RETURNS Number of significant digits / -1 for 
	error (message logged)
.REMARKS Return 0 if string contains only spaces.
	Stopped index returned in static `stopped'.
--------*/
	char	*str;	/* IN: String to scan	*/
	int	len;	/* IN: Length of str	*/
	double	*value;	/* OUT: result		*/
{
	char 	*p, *pe, *ps, x;
	int	i, nd;
	double	atof();
  
  trerror->errno = 0;
  
  *value = 0.0e0, nd = 0;
  p = str, pe = p + len;
  GobbleSpaces(p,len);

  if (p == pe)	{ trerror->errno = TRERR_VOID; FINISH; }

  ps = p;			/* Starting point of string */
  if (issign(*p))	p++;
  p += oscskip(p, pe-p, '0');	/* Skip leading zeroes, not significant */
  if (p == pe)	FINISH;		/* Zero	*/
  
  nd = oscspan((unsigned char *)p, pe-p, _DIGIT_, main_ascii), p += nd;
  if (p == pe)	goto GET_VALUE;
  
  if (*p == '.')	p++;
  if (nd == 0)			/* Skip leading zeroes	*/
	p += oscskip(p, pe-p, '0');
  i = oscspan((unsigned char *)p, pe-p, _DIGIT_, main_ascii);	/* Decimals */
  p += i, nd += i;

	/* Look for Exponent */

  if ((p < pe) && (isalpha(*p)))
  {	x = toupper(*p);
  	if ((x == 'E') || (x == 'D'))	/* Exponent */
  	{	if (p == ps)	trerror->errno = TRERR_VOID; 
  		p++;
  		if (issign(*p))	p++;
  		p += oscspan((unsigned char *)p, pe-p, _DIGIT_, main_ascii);
  	}
  }

  GET_VALUE:
  if (p == ps)	trerror->errno = TRERR_VOID; 
  x = *p, *p = '\0', *value = atof(str), *p = x;
  
  FIN:
  stopped = p;
  return(nd);
}
  
/*===========================================================================*/
int tr_af(str, len, value)
/*++++++
.PURPOSE Converts a string to a floating point.
	Input is assumed to be in decimal.
.RETURNS Number of significant digits / -1 for 
	error (message logged)
.REMARKS Return 0 if string contains only spaces.
--------*/
	char	*str;	/* IN: String to scan	*/
	int	len;	/* IN: Length of str	*/
	double	*value;	/* OUT: result		*/
{
	char 	*p, *pe;
	int	nd;
  
  p = str, pe = p + len;
  nd = traf(p, len, value);
  if (nd < 0)	FINISH;

  p = stopped;
  GobbleSpaces(p, pe-p);

  if (p != pe)
  {	trerror->errno = TRERR_DIGIT, 
	trerror->str = str,
	trerror->len = len,
	trerror->offset = p - str,
	nd = -1;
	tr_error();
	FINISH;
  }
  
  FIN:
  if ( (nd == 0) && (trerror->errno == 0))	nd = 1;
  return(nd);
}
  
/*===========================================================================*/
int tr_af1(str, len, value, n)
/*++++++
.PURPOSE Converts a string to a vector of numbers.
	Numbers may be separated by blanks or any punctuation character,
.RETURNS Number of found numbers (<= n) / -1 for
	error (message logged)
.REMARKS Return 0 if string contains only spaces.
--------*/
	char	*str;	/* IN: String to scan	*/
	int	len;	/* IN: Length of str	*/
	double	*value;	/* OUT: result		*/
	int	n;	/* IN: Number of values	*/
{
	char 	*p, *pe;
	int	i;

  trerror->errno = 0;

  p = str, pe = p + len;
  
  for (i=0; (p<pe) && (i < n); i++)
  {	GobbleSpaces(p, pe-p);
	if (p == pe)	break;
	traf(p, pe-p, value+i);
	if (trerror->errno)	break;	/* Void number */
	p = stopped;
	if (p == pe)		continue;
	if (isspace(*p))	continue;
	if (issign(*p))		continue;
	if (*p == '.')		continue;
	p++;
  }

  if (trerror->errno == 0)	
  {	GobbleSpaces(p, pe-p);
  	if (p < pe)	trerror->errno = TRERR_TOOMANY;
  }
  if (trerror->errno)
  {	trerror->str = str, trerror->len = len, 
  	trerror->offset = (p - str);
  	tr_error();
  }
  
  return((trerror->errno ? -1 : i));
}  

/*===========================================================================*/
int tr_afn(str, len, value, n)
/*++++++
.PURPOSE Converts a string to a vector of double numbers.
	Numbers may be separated by blanks or any punctuation character.
.RETURNS  n for success / -1 for failure
.REMARKS 
--------*/
	char	*str;	/* IN: String to scan	*/
	int	len;	/* IN: Length of str	*/
	double	*value;	/* OUT: array result	*/
	int	n;	/* IN: Number of values	*/
{
	int	i;

  i = tr_af1(str, len, value, n);

  if ((i >= 0) && (i < n))	/* Too few numbers */
  {	trerror->errno = TRERR_TOOFEW;
	trerror->str = str, trerror->len = len, 
  	trerror->offset = len;
  	tr_error();
  }
  
  return((trerror->errno ? -1 : i));
}
