/************************************************************************* * (C) 2008 AITNET ltd - Sofia/Bulgaria - * by Michael Pounov * * $Author: misho $ * $Id: parse.c,v 1.5 2010/03/22 15:15:48 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); unquot(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; }