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

	int cfgEnumSections(int mode, CFG_ENUMFUNC fct, void * const arg);

	enumerate all sections

	Known bugs:
		currently the INI files must not be changed when within
		a Enum() function

ob(ject): cfgEnumSections
su(bsystem): inifile/2
sh(ort description): Enumerate all sections of the INI file
lo(ng description): Enumerate all sections of the currently opened INI file
 and call a callback function with the found names.
re(lated to):
fi(le): cfgies.c
in(itialized by): cfgInitINI

*/

#include "initsupl.loc"

#ifndef _MICROC_
#include <stdlib.h>
#endif
#include "inifile.loc"
#include "supplio.h"
#include "dynstr.h"

#include "suppldbg.h"

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

int cfgEnumSections(int mode, Cfg_secEnumFunc fct, void * const arg)
{	int userfile;		/* user vs. system INI file */
	int rv;
	inifstru *f;
	Cfg_secEnumData keyinfo;
	int mods;
#define pos keyinfo.cfgi___vpos

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

	assert(fct);

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

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

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

	Frewind(f->cfgi_fp);			/* start at begining of file */
	FFgetpos(f->cfgi_fp, I(curpos));
	keyinfo.cfgi_keyname = 0;	/* first key is always 0 */
	chkHeap

	do {
		if(userfile				/* in user file --> enum all sections */
		 || mode != CFG_FSTD	/* not standard mode --> enum all sections */
		 		/* no user section --> enum it */
		 || cfgHasUserSection(keyinfo.cfgi_keyname) == CFG_ERR_KEY) {
			chkHeap
			/* complete the key information structure */
			Fposcpy(aS(keyinfo.cfgi___kpos), aS(I(curpos)));
			keyinfo.cfgi_location = userfile;
			chkHeap

			/* preserve the current position in order to restart here
				when the callback function returns */
			if(FFgetpos(f->cfgi_fp, pos))
				rv = CFG_ERR_ACC;
			else rv = (fct)(aS(keyinfo), arg);	/* invoke callback fct */
			chkHeap

			if(rv != CFG_ERR_NONE)			/* terminate Enum() */
				goto errRet;

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

			/* make sure Enum() restarts at the position after the
				previously found section */
			if(FFsetpos(f->cfgi_fp, pos)) {
				rv = CFG_ERR_ACC;
				goto errRet;
			}
			chkHeap
		}
		chkHeap

		/* advance to next section */
		switch(rv = cfgi_nxtSec(f->cfgi_fp)) {
		case CFG_ERR_NONE:		/* next key found */
			break;
		case CFG_ERR_KEY:		/* advance to next INI file */
			chkHeap
			StrFree(keyinfo.cfgi_keyname);
			chkHeap

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

			DBG_RETURN_I( CFG_ERR_NONE)	/* all done */

		default:
			goto errRet;
		}
		chkHeap

	} while(StrCpy(keyinfo.cfgi_keyname, I(data)));
	chkHeap

	DBG_RETURN_I(CFG_ERR_MEM)

errRet:
	chkHeap
	free(keyinfo.cfgi_keyname);
	chkHeap
	DBG_RETURN_I(rv)
}
