/*
    This file is part of SUPPL - the supplemental library for DOS
    Copyright (C) 1996-2000 Steffen Kaiser

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $RCSfile: CFGI_PV.C $
   $Locker: ska $	$Name:  $	$State: Exp $

	int cfgi_parseVal(const char * const name);

	Locate, parse and decompose value

	The last process includes:
		1) strip a trailing comment from the data
			(available with GetValComment())
		2) strip leading and trailing whitespaces
		3) parse quotes
		4) expand environment variables if value is of expandable type
		5) squeeze multiple non-quoted whitespaces into a single space

	Return:	cfg error code

ob: cfgi_parseVal
ty: L
su: inifile/2
sh: Locate, parse and decompose a value
lo: Searches the whole current section for a specified value, break it into
	components (value, data, type and trustlevel) and decompose the value.\par
	The latter action includes:
	\item strip the comment from the data,
	\item strip leading and trailing whitespaces,
	\item parse quotes,
	\item expand environment variables, if the type allows so,& finally
	\item squeeze multiple non-quoted whitespaces into a single space.
re: cfgi_quoteString
fi: cfgi_pv.c
in:

*/

#include "initsupl.loc"

#ifndef _MICROC_
#endif
#include <ctype.h>
#include "inifile.loc"
#include "dynstr.h"
#include "str.h"
#include "environ.h"

	/* during copy of the buffer the new buffer grows in chunks of
		this size */
#define BUFCHGSIZE 64

#include "suppldbg.h"

#ifdef RCS_Version
static char const rcsid[] = 
	"$Id: CFGI_PV.C 1.4 2001/02/27 01:27:56 ska Exp ska $";
#endif

int cfgi_parseVal(const char * const name)
{	int rv;
	char *buf;			/* buffer is duplicated into this temp buffer */
	size_t len;			/* length of buf */
	char *h;			/* pointer into I(buf) */
	char *s;
	size_t i, lastSpace;
	int ch, inquote;

	DBG_ENTER("cfgi_parseVal", Suppl_inifile2)
	DBG_ARGUMENTS( ("name=\"%s\"", name) )

	chkHeap
	if((rv = cfgHasValue(name)) == CFG_ERR_NONE
	 && !I(decomposed)) {
		chkHeap
		/* has value --> decompose it */

		buf = strdup(I(value));		/* temporary buffer only holds valname */
		chkHeap
		if(!buf)
			DBG_RETURN_I( CFG_ERR_MEM)
		h = skipws(I(data));		/* first byte of data */
		len = i = strlen(buf) + 1;	/* first data byte in new buffer */
		lastSpace = inquote = 0;
		chkHeap

		while((ch = *h++) != '\0') {
			chkHeap
			if(ch == CFG_QUOTE) {
				if(inquote) {
					if(*h == CFG_QUOTE) {	/* in quotes, two quotes
										are translated into one quote */
						++h;
						goto putCh;
					} else {			/* end of quote */
						inquote = 0;
					}
				} else {				/* start quote */
					inquote = ch;
				}
				continue;
			}

			if(ch == '%' && CFG_TISEXPAND(I(type))) {
				/* expand environment variables */
				if(*h == '%') {			/* single percent sign */
					++h;
					goto putCh;
				}
				chkHeap
				if((s = strchr(h, '%')) == 0)	/* error --> ignore */
					goto putCh;
				*s = '\0';			/* now, h points to the variable name */
				h = env_fetch(0, h);
				chkHeap
				if(h && *h) {		/* not empty variable */
					chkHeap
					if(!StrChg(buf, len = i + strlen(h) + 2))
						DBG_RETURN_I( CFG_ERR_MEM)
					chkHeap
					strcpy(&buf[i], h);
					chkHeap
					i = len - 2;
				}
				h = s + 1;
				lastSpace = 0;	/* zero-length variable following a space */
				continue;
			}

			if(ch == CFG_COMMENT && !inquote) {		/* start of comment */
				/* all the rest of the input buffer is comment */

				/* strip trailing space */
				if(lastSpace == i - 1) {	/* see below */
					--i;
				}

				chkHeap
				if(!StrChg(buf, i + strlen(h) + 1))
					DBG_RETURN_I( CFG_ERR_MEM)
				chkHeap
				buf[i] = '\0';		/* end of data */
				strcpy(I(comment) = &buf[++i], h);
				chkHeap
				goto alldone;
			}

			if(isspace(ch) && !inquote) {		/* squeeze them */
				chkHeap
				lastSpace = i;		/* to be able to strip it */
				h = skipws(h);
				chkHeap
				ch = ' ';
			}

putCh:		/* add one character */
			chkHeap
			if(i >= len && !StrChg(buf, len += BUFCHGSIZE))
				DBG_RETURN_I( CFG_ERR_MEM)
			chkHeap
			buf[i++] = ch;
		}

		if(lastSpace == i - 1) {	/* last character is non-quoted
				space --> strip it */
			/* lastSpace is initially 0 (zero), but i is always > 2,
				because of the value name at the beginning of the
				buffer */
			--i;
		}

		chkHeap
		/* Reallocate the buffer to the smallest possible size */
		if(!StrChg(buf, i + 1))
			DBG_RETURN_I( CFG_ERR_MEM)
		chkHeap
		buf[i] = '\0';
		I(comment) = &buf[i];		/* no comment */
		chkHeap

alldone:	/* update the fields within the inistru */
		chkHeap
		StrRepl(I(buf), buf);
		chkHeap
		I(data) = strchr(I(value) = buf, '\0') + 1;
		chkHeap
		I(decomposed) = 1;
	}

	DBG_RETURN_I( rv)
}
