/*
    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: CFGIEV.C $
   $Locker: ska $	$Name:  $	$State: Exp $

	int cfgEnumValues(Cfg_valEnumFunc fct, void * const arg);

	Enumerate all values of the current section.
	If the current section is changed within the callback function,
	the next iteration will fail. The same when the INI file is
	modified.
	Multiple Enum()s over the same setcion is possible, though,
	although each time a callback function is invoked or returns,
	the current value changes.

	Return: cfg error code

ob(ject): cfgEnumValues
su(bsystem): inifile/2
sh(ort description): Enumerate all values of the current section
lo(ng description): Enumerate all values of the current section
 and call a callback function with the found names.\par
 There can be multiple cfgEnumValues's simultaneously active.
re(lated to): cfgEnumSections
fi(le): cfgiev.c
in(itialized by): cfgInitINI

*/

#include "initsupl.loc"

#ifndef _MICROC_
#endif
#include "inifile.loc"
#include "supplio.h"

#include "suppldbg.h"

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

int cfgEnumValues(int mode, Cfg_valEnumFunc fct, void * const arg)
{	int userfile;		/* user vs. system INI file */
	int rv;
	inifstru *f;
	fpos_t pos;
	int mods;

	DBG_ENTER("cfgEnumValues", Suppl_inifile2)
	DBG_ARGUMENTS( ("mode=%x", mode) )

	assert(fct);

	chkHeap
	I(value) = 0;		/* indicate that there is no curr value */
	mods = I(modifications);	/* preserve the current modification
									counter to detect changes of the
									user INI file, while Enum() is active */

	userfile = 0;
	if(mode != CFG_FSYSTEM) {		/* try user INI file */
		if(hasKey(usrini)) {
			userfile = 1;
			f = aS(usrini);
		}
	}
	chkHeap

redo:
	if(!userfile) {					/* no user file available */
		if(mode == CFG_FUSER		/* only userfile */
		 || !hasKey(sysini))
			DBG_RETURN_I( 0)				/* everything scanned */
		f = aS(sysini);
	}
	chkHeap

	Fposcpy(aS(pos), aS(f->cfgi_pos));	/* start at beginning of the section */

	do {
		if(FFsetpos(f->cfgi_fp, pos))
			DBG_RETURN_I( CFG_ERR_ACC)

nxtValue:
		chkHeap
		/* advance to next value */
		if((rv = cfgi_nxtVal(f->cfgi_fp)) == CFG_ERR_END) {
			chkHeap
			/* advance to next INI file */

			if(--userfile >= 0)	/* still have a valid INI file */
				goto redo;

			DBG_RETURN_I( CFG_ERR_NONE)	/* all done */
		}

		if(rv != CFG_ERR_NONE)		/* some error */
			DBG_RETURN_I( rv)

		chkHeap
		if(userfile == 0 && mode == CFG_FSTD) {
			/* currently active: system INI file and in standard mode
				--> check that this value is not available in user INI file */

			/* Problem: cfgHasUserValue() will modify the current value
				Therefore the value is re-read from the system INI file
				if necessary. pos holds the position of the start of that
				line. */
			if(cfgHasUserValue(0) == CFG_ERR_NONE) {
				chkHeap
				/* in user INI file --> ignore --> goto nxt value */
				if(FFgetpos(f->cfgi_fp, pos))
					DBG_RETURN_I( CFG_ERR_ACC)
				goto nxtValue;
			}

			/* not in user INI --> re-read it */
			if(FFsetpos(f->cfgi_fp, pos))
				DBG_RETURN_I( CFG_ERR_ACC)

			/* Because this call succeeded once, it must succeed now, or
				something is totally wrong */
			chkHeap
			if((rv = cfgi_nxtVal(f->cfgi_fp)) != CFG_ERR_NONE)
				DBG_RETURN_I( rv)
			chkHeap
		}

		/* new value cached */
		I(valLocation) = userfile;

		/* preserve the current position in order to restart here
			when the callback function returns */
		if(FFgetpos(f->cfgi_fp, pos))
			DBG_RETURN_I( CFG_ERR_ACC)

		/* invoke callback fct */
		chkHeap
		if((rv = (fct)(arg)) != CFG_ERR_NONE)		/* terminate Enum() */
			DBG_RETURN_I( rv)
		chkHeap

		/* Check if the INI file was changed, what would mean that
			the internally cached position to restart is no longer
			valid. Because the system INI file cannot change,
			this test is omitted there. */
	} while(!userfile || I(modifications) == mods);
	chkHeap

	DBG_RETURN_I( CFG_ERR_INICHG)
}
