/****************************************************************************/
/* Copyright 2003-2010 MBARI												*/
/****************************************************************************/
/* Summary	: Generic Parsing Routines										*/
/* Filename : parse.c														*/
/* Author	: Robert Herlien (rah)											*/
/* Project	: Respirometers													*/
/* Revision : 1.0															*/
/* Created	: 09/01/2010 from config.c										*/
/*																			*/
/* MBARI provides this documentation and code "as is", with no warranty,	*/
/* express or implied, of its quality or consistency. It is provided without*/
/* support and without obligation on the part of the Monterey Bay Aquarium	*/
/* Research Institute to assist in its use, correction, modification, or	*/
/* enhancement. This information should not be published or distributed to	*/
/* third parties without specific written permission from MBARI.			*/
/*																			*/
/****************************************************************************/
/* Modification History:													*/
/* 01sep2010 rah - split off from config.c for OASIS4						*/
/* 14jul2016 rah - OASIS5 version created from OASIS4
/* $Log$
 */
/****************************************************************************/

#include <mbariTypes.h>			/* MBARI type definitions				*/
#include <mbariConst.h>			/* MBARI constants						*/
#include <oasis.h>				/* OASIS controller definitions			*/
#include <parse.h>				/* Generic parser declarations			*/

#include <fatFs/ff.h>			/* FatFs file system defns				*/
//#include <stdio.h>				/* Standard I/O library					*/
//#include <stdlib.h>				/* Standard C library					*/
#include <string.h>				/* Standard string library				*/
#include <ctype.h>				/* Standard ctypes						*/


/************************************************************************/
/* Function	   : getOneConfigLine										*/
/* Purpose	   : Get one (logical) line from input file					*/
/* Inputs	   : FILE ptr, buffer ptr, buffer len						*/
/* Outputs	   : Number of lines read (>=0) or ERROR					*/
/************************************************************************/
Int32 getOneConfigLine(FIL *fp, char *buf, int buflen)
{
	char	*p;
	Int32 lineno;

	memset(buf, 0, buflen);

	for (lineno = 0; (f_gets(buf, buflen, fp) != NULL); )
	{
		lineno++;
		if ((p = strpbrk(buf, "\n\r")) != NULL)
			*p = '\0';					/* Delete trailing CR, LF, or comment*/

		while ((p = strpbrk(buf, "()")) != NULL)
			*p = ' ';					/* Replace parens by space			*/

		p = buf;
		deblank(p);

		if ((*p != '\0') && (*p != '#'))
			return(lineno);

		buf[0] = '\0';
	}

	return((strlen(buf) > 0) ? lineno : ERROR);

} /* getOneConfigLine() */


/************************************************************************/
/* Function	   : initTokenizer											*/
/* Purpose	   : Initialize the Tokenizer to start at ptr p				*/
/* Inputs	   : Tokenizer to initialize, where to initialize it to		*/
/* Outputs	   : None													*/
/************************************************************************/
void initTokenizer(Tokenizer *tok, char *startp)
{
	tok->current = tok->next = startp;

} /* initToken() */


/************************************************************************/
/* Function	   : getNextToken											*/
/* Purpose	   : Get next token, return NULL if end of line				*/
/* Inputs	   : Ptr to Tokenizer										*/
/* Outputs	   : Ptr to next token (NULL terminated), or NULL if none	*/
/************************************************************************/
char *getNextToken(Tokenizer *tok)
{
	Reg char	*nextTok, *endOfTok;

	if ((nextTok = tok->next) == NULL)
		return(NULL);

	deblank(nextTok);
	tok->current = nextTok;

	if (*nextTok == '"')
	{
		tok->current++;
		for (endOfTok = nextTok+1; *endOfTok; endOfTok++)
		{
			if (*endOfTok == '\\')
				memcpy(endOfTok, endOfTok+1, strlen(endOfTok+1));
			else if (*endOfTok == '"')
				break;
		}
		nextTok = endOfTok;
		if (*nextTok == '"')
			nextTok++;
	}
	else if (*nextTok == '#')
		return(NULL);
	else if ((endOfTok = strpbrk(nextTok, "		,\"#\n")) != NULL)
		nextTok = endOfTok;
	else
		nextTok = NULL;

	if (nextTok)
	{
		deblank(nextTok);
		if (*nextTok == ',')
			nextTok++;
		*endOfTok = '\0';
	}

	tok->next = nextTok;
 
#ifdef DEBUG_CONFIG
	dprintf("getNextToken: current = \"%s\"  next = \"%s\"\n",
		   tok->current, tok->next);
#endif

	return(tok->current);

} /* getNextToken() */


/************************************************************************/
/* Function	   : isaTok													*/
/* Purpose	   : Determine whether ptr points to valid token			*/
/* Inputs	   : Token Ptr												*/
/* Outputs	   : FALSE if NULL string, or comma (','); else TRUE		*/
/************************************************************************/
MBool isaTok(char *tok)
{
	return(tok && *tok && (*tok != ','));

} /* isaTok() */


/************************************************************************/
/* Function	   : getDecToken											*/
/* Purpose	   : Get a decimal value from next token					*/
/* Inputs	   : Ptr to tokenizer, ptr to decimal value to fill in		*/
/* Outputs	   : Ptr to token that was parsed							*/
/************************************************************************/
char *getDecToken(Tokenizer *tok, Nat32 *valp)
{
	Reg char		*nextTok;

	nextTok = getNextToken(tok);
	if (isaTok(nextTok))
		sscanNum(nextTok, (Parm_t *)valp);

	return(nextTok);

} /* getDecToken() */


/************************************************************************/
/* Function	   : getFltToken											*/
/* Purpose	   : Get a floating point value from next token				*/
/* Inputs	   : Ptr to tokenizer, ptr to float value to fill in		*/
/* Outputs	   : Ptr to token that was parsed							*/
/************************************************************************/
char *getFltToken(Tokenizer *tok, float *valp)
{
	Reg char		*nextTok;

	nextTok = getNextToken(tok);
	if (isaTok(nextTok))
		sscanf(nextTok, " %f", valp);

	return(nextTok);

} /* getFltToken() */


/************************************************************************/
/* Function	   : strToLower												*/
/* Purpose	   : Change a string to lower case							*/
/* Inputs	   : Ptr to string											*/
/* Outputs	   : None													*/
/************************************************************************/
void strToLower(char *s)
{
	Reg char		*p;
	Reg int		c;

	for (p = s; *p; p++)
	{
		c = *p;
		if (isalpha(c))
			*p = tolower(c);
	}

} /* strToLower() */


/************************************************************************/
/* Function	   : sscanNum												*/
/* Purpose	   : Similar to sscanf(s, "%d"), but understands 0xnnn and nnnH*/
/* Inputs	   : String to scan, long int to put it in					*/
/* Outputs	   : Number of items found (0 or 1)							*/
/************************************************************************/
Int16 sscanNum(char *s, Parm_t *valp)
{
	if (strncasecmp(s, "0x", 2) == 0)
		return(sscanf(s+2, "%x", valp));

	if (strpbrk(s, "Hh") != NULL)
		return(sscanf(s, "%x", valp));

	return(sscanf(s, "%ld", valp));

} /* sscanNum() */
