File:  [ELWIX - Embedded LightWeight unIX -] / libaitcfg / src / parse.c
Revision 1.2.2.4: download - view: text, annotated - select for diffs - revision graph
Mon Oct 19 14:58:24 2009 UTC (14 years, 6 months ago) by misho
Branches: cfg3_1
Diff to: branchpoint 1.2: preferred, colored
add new feature !!!! MergeConfig
fix ConcatConfig
and add anti-loop in merge/concat features

/*************************************************************************
* (C) 2008 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
*  by Michael Pounov <misho@openbsd-bg.org>
*
* $Author: misho $
* $Id: parse.c,v 1.2.2.4 2009/10/19 14:58:24 misho Exp $
*
*************************************************************************/
#include "global.h"
#include "aitcfg.h"
#include "tools.h"


// cfgDbg() Debug/Log operation
static inline int cfgDbg(FILE *f, char *fmt, ...)
{
	int ret = 0;
	va_list lst;

	va_start(lst, fmt);
	ret = vfprintf(f, fmt, lst);
	va_end(lst);

	return ret;
}

/*
 * InvertQueue() InvertQueue order //{cfg} list of elements for revert
 * @cfg = Head list element for revert 
*/
static inline void InvertQueue(sl_config * __restrict cfg)
{
	struct tagPair *item, *next, *prev = NULL;

	for (item = cfg->slh_first; item; item = next) {
		next = item->sle_next;
		item->sle_next = prev;
		prev = item;
	}
	cfg->slh_first = prev;
}

// cfgWrite() Write to file from config list
static inline int cfgWrite(FILE *f, sl_config * __restrict cfg, int whitespace)
{
	struct tagPair *av;
	time_t tim;
	char szTime[MAX_STR + 1];
	u_char szSection[MAX_STR + 1];

	bzero(szSection, MAX_STR + 1);

	bzero(szTime, MAX_STR + 1);
	time(&tim);
	strftime(szTime, MAX_STR, "(UTC) %Y-%m-%d %H:%M:%S", gmtime(&tim));
	if (!cfgDbg(f, "## Write Config :: %s\n#\n", szTime)) {
		LOGERR;
		return -1;
	}

	InvertQueue(cfg);
	for (av = cfg->slh_first; av; av = av->sle_next) {
		if (av->psSection && strcmp((char*) av->psSection, (char*) szSection)) {
			strlcpy((char*) szSection, (char*) av->psSection, MAX_STR + 1);
			if (!cfgDbg(f, "\n[%s]\n", av->psSection)) {
				LOGERR;
				return -1;
			}
		}
		if (!av->psSection && *szSection) {
			bzero(szSection, MAX_STR + 1);
			if (!cfgDbg(f, "\n[]\n")) {
				LOGERR;
				return -1;
			}
		}

		if (whitespace) {
			if (!cfgDbg(f, "%s = %s\n", av->psAttribute, av->psValue)) {
				LOGERR;
				return -1;
			}
		} else {
			if (!cfgDbg(f, "%s=%s\n", av->psAttribute, av->psValue)) {
				LOGERR;
				return -1;
			}
		}
	}
	InvertQueue(cfg);

	bzero(szTime, MAX_STR + 1);
	time(&tim);
	strftime(szTime, MAX_STR, "(UTC) %Y-%m-%d %H:%M:%S", gmtime(&tim));
	if (!cfgDbg(f, "\n#\n## Done. :: %s\n", szTime)) {
		LOGERR;
		return -1;
	}

	return 0;
}

// ---------------------------------------------------

/*
 * ReadConfig() Read from file and add new item to config list
 * @f = file resource
 * @cfg = Head list element
 * return: 0 ok; -1 error:: can`t allocate memory
*/
int ReadConfig(FILE *f, sl_config * __restrict cfg)
{
	u_char szLine[MAX_STR + 1];
	u_char szSection[MAX_STR + 1], *psAttr, *psVal;
	int pos;
	struct tagPair *av;

	memset(szSection, 0, MAX_STR + 1);
	while (!feof(f)) {
		memset(szLine, 0, MAX_STR + 1);
		fgets((char*) szLine, MAX_STR, f);
		trim(szLine);
#ifdef __DEBUG
		cfgDbg(stdout, "DEBUG:: RAW |%s|\n", szLine);
#endif

		// End of config
		if (*szLine == '.')
			break;
		// Comment
		if (*szLine == '#' || *szLine == ';' || !*szLine)
			continue;

#ifdef __DEBUG
		cfgDbg(stdout, "DEBUG:: Clean |%s|\n", szLine);
#endif

		// Section
		if (*szLine == '[') {
			pos = strlen((char*) szLine) - 1;
			if (szLine[pos] != ']') {
#ifdef __DEBUG
				cfgDbg(stdout, "WARNING:: Ignore section %s ... not closed breket\n", szLine);
#endif
			} else {
				szLine[pos] = 0; 
				strncpy((char*) szSection, (char*) szLine + 1, MAX_STR);
#ifdef __DEBUG
				cfgDbg(stdout, "DEBUG:: Section %s\n", szSection);
#endif
			}
			continue;
		}

		// Devide pairs
		pos = strchr((char*) szLine, '=') ? strchr((char*) szLine, '=') - (char*) szLine : 0;
		if (!pos) {
#ifdef __DEBUG
			cfgDbg(stdout, "WARNING:: Ignore a/v %s ... format error!\n", szLine);
#endif
			continue;
		} else {
			av = malloc(sizeof(struct tagPair));
			if (!av) {
				LOGERR;
				return -1;
			} else {
				memset(av, 0, sizeof(struct tagPair));
				// added new element
				av->sle_next = cfg->slh_first;
				cfg->slh_first = av;
			}
			// added section name to element
			if (*szSection) {
				av->psSection = malloc(strlen((char*) szSection) + 1);
				if (!av->psSection) {
					LOGERR;
					free(av);
					return -1;
				} else
					strlcpy((char*) av->psSection, (char*) szSection, strlen((char*) szSection) + 1);
			} else
				av->psSection = NULL;

			psAttr = szLine;
			psVal = (szLine + pos + 1);
			szLine[pos] = 0;
			rtrim(psAttr);
			ltrim(psVal);
#ifdef __DEBUG
			cfgDbg(stdout, "DEBUG:: Attr(%p) ->%s size=%d Value(%p) ->%s size=%d\n", 
					psAttr, psAttr, strlen((char*) psAttr), psVal, psVal, strlen((char*) psVal));
#endif
			// added attribute to element
			av->psAttribute = malloc(strlen((char*) psAttr) + 1);
			if (!av->psAttribute) {
				LOGERR;
				free(av->psSection);
				free(av);
				return -1;
			} else
				strlcpy((char*) av->psAttribute, (char*) psAttr, strlen((char*) psAttr) + 1);
			// added value to element
			av->psValue = malloc(strlen((char*) psVal) + 1);
			if (!av->psValue) {
				LOGERR;
				free(av->psAttribute);
				free(av->psSection);
				free(av);
				return -1;
			} else
				strlcpy((char*) av->psValue, (char*) psVal, strlen((char*) psVal) + 1);
		}
	}

	return 0;
}

/*
 * WriteConfig() Write to file from items in config list
 * @f = file resource
 * @cfg = Head list element
 * return: 0 ok; -1 error:: can`t write to file
*/
int WriteConfig(FILE *f, sl_config * __restrict cfg)
{
	return cfgWrite(f, cfg, 1);
}

/*
 * cfg_WriteConfig() Write to file from items in config list without whitespaces!
 * @f = file resource
 * @cfg = Head list element
 * return: 0 ok; -1 error:: can`t write to file
*/
int cfg_WriteConfig(FILE *f, sl_config * __restrict cfg)
{
	return cfgWrite(f, cfg, 0);
}

/*
 * ConcatConfig() Concat two list in one
 * @cfg = Head list element of main list
 * @add_cfg = Head list element of added list
 * return: 0 ok; -1 error:: can`t concat lists
*/
int ConcatConfig(sl_config * __restrict cfg, sl_config * __restrict add_cfg)
{
	struct tagPair *item;
	int ret = 0;

	if (!cfg || !add_cfg)
		return -1;

	for (item = cfg->slh_first; item->sle_next; item = item->sle_next);
	item->sle_next = add_cfg->slh_first;

	add_cfg->slh_first = NULL;

	return ret;
}

/*
 * MergeConfig() Marge two list in one cfg and destroy add_cfg
 * @cfg = Head list element of main list
 * @add_cfg = Head list element of merged list (destroy after all!)
 * return: 0 ok; -1 error:: can`t merge lists
*/
int MergeConfig(sl_config * __restrict cfg, sl_config * __restrict add_cfg)
{
	struct tagPair *item, *merge, *add_next, *next = NULL;
	int flg;

	if (!cfg || !add_cfg)
		return -1;

	item = add_cfg->slh_first;
	while (item) {
		add_next = item->sle_next;

		for (flg = 0, merge = cfg->slh_first, next = merge->sle_next; next; 
				merge = merge->sle_next, next = merge->sle_next) {
			if (!merge->psSection && !item->psSection) {
				flg = 1;
				merge->sle_next = item;
				item->sle_next = next;
				break;
			}
			if (merge->psSection && item->psSection && 
					!strcmp((char*) merge->psSection, (char*) item->psSection)) {
				flg = 1;
				merge->sle_next = item;
				item->sle_next = next;
				break;
			}
		}

		if (!flg) {
			if (!merge->sle_next) {
				merge->sle_next = item;
				item->sle_next = NULL;
			} else
				return -1;
		}

		item = add_next;
	}

	add_cfg->slh_first = NULL;

	return 0;
}

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>