/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * COPYING NOTES
 *
 * parser.c -- Function to parserize a text file structure like MS'.ini
 *
 * Copyright (C) 2003 Roberto A. Foglietta <robang@libero.it>
 * Copyright (C) 2003 GEA-Automotive <fogliettar@gea-automotive.com>
 *
 *   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.
 *
 *   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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 */

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * REVISION NOTES:
 *
 * released 22-05-2003 by Roberto A. Foglietta
 * bugfixed 10-06-2003 by Roberto A. Foglietta
 * bugfixed 26-06-2003 by Roberto A. Foglietta
 * static   27-06-2003 by Roberto A. Foglietta
 * english  03-07-2003 by Roberto A. Foglietta
 *
 */


#include <stdio.h>
#ifndef  __USE_GNU
# define __USE_GNU
#endif
#include <string.h>
#include <stdlib.h>
#include "parser.h"
#include "debug.h"


#define PRINT_RET(i) if(debug && cast[i] != NULL) {		\
				PRINTF("ret[%d] = '", i); 	\
				printf(cast[i], ret[i]); 	\
				PRINTF("'\n");			\
			}


union alltypes *
get_mult_param_value_from_text (const char *pt, const char *pname, const char **cast)
{
	DEBUG(OFF);

	if(pt == NULL || pname == NULL || cast == NULL)
		return NULL;

	//computing how many are the parameters
	int n_par; {
		int i = 0; while(cast[i]) i++;
		if(!(n_par = i)) return NULL;
	}
	PRINTF("n_par = %d\n",n_par);


#ifdef MAX_NUM_PARSER_PARAM
	/* RAF 2003-06-27:
	 * ATTENTION ATTENTION ATTENTION ATTENTION
	 * Static definition in not multi-thread safe!
	 */
	static union alltypes ret[MAX_NUM_PARSER_PARAM]; {
		int i;
		//Initialization of parameters' vector
		for(i = 0; i < MAX_NUM_PARSER_PARAM; i++)
				ret[i].s = NULL;
	}
#else
	//Dynamic allocation of parameters' vector
	union alltypes *ret; {
		long size = (n_par+1)*sizeof(union alltypes);
		ret = (union alltypes *)malloc( size );

		if(ret == NULL) {
			return NULL;
		} else {
			//Initialization of parameters' vector
			int i;
			for(i = 0; i <= n_par; i++)
				ret[i].s = NULL;
		}
		PRINTF("unions allocated in %u bytes\n",  size);
	}
#endif

	//I will find the line of text containing the name
	//of the selected parameter and isolate the value
	const char *str = pt; {
		const char *p;
		str--; do {
			//RAF 2003-05-20: find the parameter name
			str = strstr (++str, pname);
			if (str == NULL) {
#ifndef MAX_NUM_PARSER_PARAM
				free(ret);
#endif
				return NULL;
			}
			PRINTF("str = '%s'\n", str);

			//RAF 2003-05-20: ignore the #comments
			p = str;
			while(*p != '\n' && *p != '#' && p > pt)
				p--;
			PRINTF("p = '%s'\n", p);
		} while(*p == '#');

		//RAF 2003-05-21: move on the value
		str = strstr (str, "=");
		if (str == NULL) {
#ifndef MAX_NUM_PARSER_PARAM
				free(ret);
#endif
			return NULL;
		} else str++;
		//RAF 2003-05-21: ignore the spaces around the '='
		while (*str == ' ')	str++;				//ATTENTION: prefix ha un comportamento differente
	}
	PRINTF("str = '%s'\n", str);

	//I will do a copy of the parameter value
	char *sprm; {
		const char *p = str; {
			while(*p != '\n' && *p) p++;			//ATTENTION: il file deve finire con una linea vuota
			while(str < p && *p != ';') p--;		//ATTENTION: il valore deve terminare con un ';'
		}
		sprm = (char *)strndup(str, (size_t)(p-str));
	}
	PRINTF("sprm = '%s'\n", sprm);

	//I will do an index of all parameters
#ifdef MAX_NUM_PARSER_PARAM
	char *p[MAX_NUM_PARSER_PARAM]; {
#else
	char **p; {
		p = (char **)malloc( (n_par+1)*sizeof(char *) );
		if(p == NULL) {
			free(ret);
			free(sprm);
			return NULL;
		}
#endif
		int i; p[(i=0)] = strtok(sprm, ",");
		while(i < n_par && p[i]) {
			PRINTF("p[%d] = '%s'\n", i, p[i]);
			p[++i] = strtok(NULL, ",");
		}
	}

	//I will fill the return vector
	int i = 0;
	while(i < n_par && cast[i]) {
		PRINTF("%d/%d -- p = '%s', cast = '%s'\n", i+1,n_par,p[i],cast[i]);
		if(p[i]) { //RAF 2003-06-26: bugfix
			ret[i] = back_cast_param_from_test(p[i], cast[i]);
		} else
			ret[i].s = NULL;
		PRINT_RET(i);
		i++;
	}
	PRINTF("ret[%d] = '%s'\n", i, ret[i].s);

#ifndef MAX_NUM_PARSER_PARAM
	free(p);	//RAF-2003-05-10: fix a memory leak!
#endif
	free(sprm);

	/* ATTENTION:
	 * User who called this function has to free
	 * the ret vector and every ret[i].s strings
	 */
	return ret;
}


/* RAF 2003-05-22: allowed type of parameter value
 * %u, %d, %x, %f, %s, %lu, %ld, %lx, %lf
 */

union alltypes
back_cast_param_from_test(char *str, const char *cast)
{
	DEBUG(OFF);
	union alltypes var;

	if(str == NULL || cast == NULL) {
		var.s = NULL;
		return var;
	}

	PRINTF("str = '%s'\ncast = '%s'\n", str, cast);

	switch (cast[1]) {
	case 'u':
		sscanf (str, "%d", &(var.u));
		break;

	case 'x':
		if (!strncasecmp (str, "0x", 2))
			str += 2;
		sscanf (str, "%x", &(var.u));
		break;

	case 'l':
		switch (cast[2]) {
		case 'f':
			sscanf (str, "0x%lf", &(var.lf));
			break;

		case 'x':
			if (!strncasecmp (str, "0x", 2))
				str += 2;
			sscanf (str, "%lx", &(var.lu));
			break;

		case 'u':
			sscanf (str, "%lu", &(var.lu));
			break;

		case 'd':
			sscanf (str, "%ld", &(var.ld));
			break;

		default:
			var.s = NULL;
			break;
		}
		break;

	case 's':
		//RAF 2003-05-22: eventually I remove the quotes
		var.s = strchr(str, '"');
		PRINTF("var.s = '%s'\n", var.s);
		if(var.s == NULL) {
			var.s = strdup(str);
		} else {
			char *p = var.s;
			var.s = strdup(++p);
			PRINTF("var.s = '%s'\n", var.s);
			p = strchr(var.s, '"');
			if(p) *p = 0;
		}
		PRINTF("var.s = '%s'\n", var.s);
		break;

	case 'f':
		sscanf (str, "%f", &(var.f));
		PRINTF ("value = %f\n", var.lf);
		break;

	case 'd':
		sscanf (str, "%d", &(var.d));
		break;

	default:
		var.s = NULL;
		break;
	}

	return var;
}

char *
grab_section_from_text (const char *pt, const char *name)
{
	int debug = 0;
	const char *p = pt;

	if (name == NULL) {
		p = strstr (p, "]");
		if (p == NULL)
			return NULL;
		else {
			p++;
			/* RAF 2003-01-08:
			 * take care of doing a distinction
			 * between [section] and text which
			 * contains '[' and ']' characters.
			 */
			while (*p != '\n' && *p != '"')
				p++;
			if (*p == '"')
				p = grab_section_from_text (p, NULL);
			PRINTF ("<(%s)>\n", p);
		}
	} else
		do {
			p = strstr (p, "[");
			if (p == NULL)
				return NULL;
			else {
				p++;
				while (*p == ' ')
					p++;
			}
			PRINTF ("p:<<%s>>\n", p);

			if (!strncasecmp (p, name, strlen (name))) {
				/* RAF 2003-01-08:
				 * take care of doing a distinction
				 * between [section] and text which
				 * contains '[' and ']' characters.
				 */
				while (*p != '\n' && *p != '"' && *p != ']')
					p++;
				if (*p != '"' && *p != '\n')
					break;
			}
		} while (p != NULL);

	return (char *)p;
}


char *
dup_n_separate_section (const char *p)
{
	int debug = 0;
	char *pe, *pc, *pi;

	if (p != NULL) {
		pe = strstr (p, "[");
		if (pe == NULL)
			pc = strdup (p);
		else {
			/* RAF 2003-01-08:
			 * take care of doing a distinction
			 * between [section] and text which
			 * contains '[' and ']' characters.
			 */
			pi = pe;
			while (*pi != '\n' && *pi != '"')
				pi++;

			if (*pi == '\n')
				pc = (char *) strndup (p, (size_t) (pe - p - 1));
			else {
				pe = strstr (pi, "[");
				pc = (char *) strndup (p, (size_t) (pe - p - 1));
			}
			PRINTF ("<{%s}>\n", pc);
		}
	} else
		pc = NULL;

	return pc;
}