/* $Id: prseng.c 1521 2005-12-13 21:55:25Z mipsator $ */

/*
 * Copyright (c) 2005 Damien Couderc
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *    - Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    - Redistributions in binary form must reproduce the above
 *      copyright notice, this list of conditions and the following
 *      disclaimer in the documentation and/or other materials provided
 *      with the distribution.
 *    - Neither the name of the copyright holder(s) nor the names of its
 *      contributors may be used to endorse or promote products derived
 *      from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 */


#include <sys/types.h>
#include <stdlib.h>

#include "compat/pmk_stdio.h"
#include "compat/pmk_string.h"
#include "prseng.h"


/*#define DEBUG_PRSENG	1*/


/*****************
 * prseng_init() *
 ***********************************************************************
 DESCR
	initialize parsing engine from a file

 IN
	fp :	file descriptor
	data :	extra data to transmit or NULL

 OUT
	parsing engine structure or NULL
 ***********************************************************************/

prseng_t *prseng_init(FILE *fp, void *data) {
	prseng_t	*ppe;
	size_t		 s;

	ppe = (prseng_t *) malloc(sizeof(prseng_t));
	if (ppe != NULL) {
		/* init the buffer */
		fseek(fp, 0, SEEK_SET);
		s = fread((void *) ppe->buf, sizeof(char),
				(sizeof(ppe->buf ) - 1), fp);

		/* on error return NULL */
		if (ferror(fp) != 0) {
			free(ppe);
			return(NULL);
		}

		/* end the string */
		ppe->buf[s] = CHAR_EOS;

		/* extra data that could be needed */
		ppe->data = data;

		/* misc init */
		ppe->fp = fp;
		ppe->eof = false;
		ppe->err = false;
		ppe->str = NULL;
		ppe->cur = ppe->buf;
		ppe->linenum = 1;
		ppe->offset = 0;
	}

	return(ppe);
}


/*********************
 * prseng_init_str() *
 ***********************************************************************
 DESCR
	initialize parsing engine from a string

 IN
	str :	string to parse
	data :	extra data to transmit or NULL

 OUT
	parsing engine structure or NULL
 ***********************************************************************/

prseng_t *prseng_init_str(char *str, void *data) {
	prseng_t	*ppe;

	ppe = (prseng_t *) malloc(sizeof(prseng_t));
	if (ppe != NULL) {
		/* init the buffer */
		strlcpy(ppe->buf, str, sizeof(ppe->buf)); /* no check */

		/* keep track of start of line */
		ppe->str = str;

		/* extra data that could be needed */
		ppe->data = data;

		/* misc init */
		ppe->fp = NULL;
		ppe->eof = true;
		ppe->err = false;
		ppe->cur = ppe->buf;
		ppe->linenum = 1;
		ppe->offset = 0;
	}

	return(ppe);
}


/********************
 * prseng_destroy() *
 ***********************************************************************
 DESCR
	destroy parsing engine structure

 IN
	ppe :	structure to destroy

 OUT
	NONE
 ***********************************************************************/

void prseng_destroy(prseng_t *ppe) {
	free(ppe);
}


/*******************
 * prseng_update() *
 ***********************************************************************
 DESCR
	update parsing engine buffer

 IN
	ppe :	parsing engine structure

 OUT
	boolean
 ***********************************************************************/

bool prseng_update(prseng_t *ppe) {
	size_t	 s;

	/* if the cursor didn't move ... */
	if (ppe->cur == ppe->buf) {
		/* then skip update */
		return(true);
	}

	/* compute offset */
	ppe->offset = (ppe->cur - ppe->buf) + ppe->offset;

	if (ppe->fp != NULL) {
		/* set the reading pointer at desired offset */
		fseek(ppe->fp, ppe->offset, SEEK_SET);

		if (feof(ppe->fp) != 0) {
			ppe->eof = true;
		}

		/* fill buffer with size - 1 characters */
		s = fread((void *) ppe->buf, sizeof(char),
				(sizeof(ppe->buf ) - 1), ppe->fp);

		/* ferror ? */
		if (ferror(ppe->fp) != 0) {
			ppe->err = true;
			return(false);
		}

		/* put EOS right after the last read char */
		ppe->buf[s] = CHAR_EOS;

		/* check if end of file has been reached */
		if (feof(ppe->fp) != 0) {
			ppe->eof = true;
		}
	} else {
		strlcpy(ppe->buf, (ppe->str + ppe->offset),
				sizeof(ppe->buf)); /* no check ? */
	}

	/* rewind cursor to the beginning of the buffer */
	ppe->cur = ppe->buf;

	/* buffer filled, return pointer to the first character */
	return(true);
}


/****************
 * prseng_eof() *
 ***********************************************************************
 DESCR
	check for end of file

 IN
	ppe :	parsing engine structure

 OUT
	boolean
 ***********************************************************************/

bool prseng_eof(prseng_t *ppe) {
	if (ppe->err == true) {
		/* file error, consider it as an end of file */
		return(true);
	}

	/* not reached end of file neither get end of string */
	if ((ppe->eof == false) || (*ppe->cur != '\0')) {
		return(false);
	}

	/* end of file and buffer */
	return(true);
}


/*********************
 * prseng_get_char() *
 ***********************************************************************
 DESCR
	get character of parsing cursor

 IN
	ppe :	parsing engine structure

 OUT
	character
 ***********************************************************************/

char prseng_get_char(prseng_t *ppe) {
	/* return character at the current cursor position */
	return(*ppe->cur);
}


/**********************
 * prseng_next_char() *
 ***********************************************************************
 DESCR
	set parsing cursor to next character

 IN
	ppe :	parsing engine structure

 OUT
	boolean
 ***********************************************************************/

bool prseng_next_char(prseng_t *ppe) {
	if (*ppe->cur == '\n') {
#ifdef DEBUG_PRSENG
	debugf("prseng_next_char() : new line = %d", ppe->linenum);
#endif
		ppe->linenum++;
	}

	/* set the cursor to the next char */
	ppe->cur++;

#ifdef DEBUG_PRSENG
	debugf("prseng_next_char() : new char = '%c'.", *ppe->cur);
#endif

	/* if end of string try to update buffer */
	if (*ppe->cur == CHAR_EOS) {
		if (prseng_update(ppe) == false) {
			return(false);
		}
	}


	return(true);
}


/**********************
 * prseng_test_char() *
 ***********************************************************************
 DESCR
	test character at the parsing cursor position

 IN
	ppe :	parsing engine structure
	c :		char to compare with

 OUT
	boolean
 ***********************************************************************/

bool prseng_test_char(prseng_t *ppe, char c) {
	if (*ppe->cur == c) {
		return(true);
	}

	return(false);
}


/***************************
 * prseng_test_idtf_char() *
 ***********************************************************************
 DESCR
	test if character at the parsing cursor is an identifier character
	contained in the given string

 IN
	pstr :	string of identifier characters
	c :		character to test

 OUT
	boolean
 TODO
	XXX do it directly with ppe ????
 ***********************************************************************/

bool prseng_test_idtf_char(char *pstr, char c) {
	/* parse the allowed characters string */
	while (*pstr != CHAR_EOS) {
		if (*pstr == c) {
			/* character matches */
			return(true);
		}

		/* next character */
		pstr++;
	}

	/* not found */
	return(false);
}


/*********************
 * prseng_get_idtf() *
 ***********************************************************************
 DESCR
	get an identifier from the actual parsing cursor position

 IN
	ppe :	parsing engine structure
	pbuf :	identifier storage buffer
	s :		size of buffer
	pstr :	identifier allowed characters

 OUT
	boolean
 ***********************************************************************/

bool prseng_get_idtf(prseng_t *ppe, char *pbuf, size_t s, char *pstr) {
	/* leave space for the end of string character */
	s--;

	/* loop while we have allowed char and enough place in the buffer */
	while ((prseng_test_idtf_char(pstr, *ppe->cur) == true) && (s > 0)) {
		/* copy character */
		*pbuf = *ppe->cur;

		/* update buffer cursor */
		pbuf++;
		s--;

		/* next character */
		if (prseng_next_char(ppe) == false) {
			*pbuf = CHAR_EOS;
			return(false);
		}
	}

	*pbuf = CHAR_EOS;
/*
	if (prseng_test_idtf_char(pstr, *ppe->cur) == true) {
		return(false);
	}
*/
	return(true);
}



syntax highlighted by Code2HTML, v. 0.9.1