Diff for /libaitcfg/src/parse.c between versions 1.6 and 1.19

version 1.6, 2011/05/01 17:24:28 version 1.19, 2021/11/26 01:15:03
Line 12  terms: Line 12  terms:
 All of the documentation and software included in the ELWIX and AITNET  All of the documentation and software included in the ELWIX and AITNET
 Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>  Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
   
Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011Copyright 2004 - 2021
         by Michael Pounov <misho@elwix.org>.  All rights reserved.          by Michael Pounov <misho@elwix.org>.  All rights reserved.
   
 Redistribution and use in source and binary forms, with or without  Redistribution and use in source and binary forms, with or without
Line 44  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF TH Line 44  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF TH
 SUCH DAMAGE.  SUCH DAMAGE.
 */  */
 #include "global.h"  #include "global.h"
 #include "aitcfg.h"  
   
   
// cfgDbg() Debug/Log operation/*
static inline int cfgDbg(FILE *f, char *fmt, ...) * cfgReadConfig() - Read file and add new item at config root
  *
  * @f = File resource
  * @cfg = Config root
  * return: -1 error or 0 ok
  */
 int
 cfgReadConfig(FILE *f, cfg_root_t * __restrict cfg)
 {  {
        int ret = 0;        char line[BUFSIZ], origin[BUFSIZ];
        va_list lst;        struct tagCfg *av = NULL;
         int flg = 0;
         char *psAttr, *psVal, szSection[STRSIZ] = { 0 };
         FILE *ff;
   
        va_start(lst, fmt);        if (!f || !cfg) {
        ret = vfprintf(f, fmt, lst);                cfg_SetErr(EINVAL, "Invalid parameter(s)");
        va_end(lst);                return -1;
         }
   
        return ret;        while (!feof(f)) {
}                memset(line, 0, sizeof line);
                 fgets(line, sizeof line - 1, f);
 #ifdef SUPPORT_USER_EOF
                 /* check for user end-of-file */
                 if (line[0] == '.' && line[1] == '\n')
                         break;
 #endif
                 if (!(psAttr = strpbrk(line, "\r\n"))) {
                         /* skip line, too long */
                         continue;
                 } else {
                         *psAttr = 0;
                         strlcpy(origin, line, sizeof origin);
                         str_Trim(line);
                 }
   
/*                if (flg) {
 * InvertQueue() InvertQueue order //{cfg} list of elements for revert                        /* continues line */
 * @cfg = Head list element for revert                         if (!av)
*/                                continue;
static inline void InvertQueue(sl_config * __restrict cfg)                        else
{                                psAttr = line + strlen(line) - 1;
        struct tagPair *item, *next, *prev = NULL;                        if (*psAttr == '\\')
                                 *psAttr = 0;
                         else
                                 flg = 0;
                         /* concat line to value */
                         AIT_SET_STRCAT(&av->cfg_val, line);
                         if (!flg && AIT_ADDR(&av->cfg_val))
                                 str_Unquot((char*) AIT_GET_STR(&av->cfg_val));
   
        for (item = cfg->slh_first; item; item = next) {                        /* read include file */
                next = item->sle_next;                        if (!flg && AIT_ADDR(&av->cfg_val) && 
                item->sle_next = prev;                                        *AIT_GET_STR(&av->cfg_attr) == '%' && 
                prev = item;                                        !strcmp(AIT_GET_STR(&av->cfg_attr), "%include")) {
                                 ff = fopen(AIT_GET_STR(&av->cfg_val), "r");
                                 if (ff) {
                                         cfgReadConfig(ff, cfg);
                                         fclose(ff);
                                 } else
                                         EDEBUG(7, "Error:: Can't open %s file", 
                                                         AIT_GET_STR(&av->cfg_val));
                         }
                         continue;
                 }
 
                 /* *NEW PAIR* alloc new pair element */
                 av = e_malloc(sizeof(struct tagCfg));
                 if (!av) {
                         cfg_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
                         return -1;
                 } else {
                         memset(av, 0, sizeof(struct tagCfg));
                         CFG_RC_LOCK(cfg);
                         TAILQ_INSERT_TAIL(cfg, av, cfg_next);
                         CFG_RC_UNLOCK(cfg);
                 }
 
                 /* check for comment or empty line */
                 if (!*line || *line == '#' || *line == ';') {
                         AIT_SET_STR(&av->cfg_val, line);
                         continue;
                 }
 
                 /* check for continues line */
                 psAttr = line + (*line ? strlen(line) : 1) - 1;
                 if (*psAttr == '\\') {
                         *psAttr = 0;
                         flg = 1;
                 }
 
                 /* section */
                 if (*line == '[') {
                         psAttr = line + strlen(line) - 1;
                         if (*psAttr == ']') {
                                 *psAttr = 0; 
                                 flg = 0;
                                 strlcpy(szSection, line + 1, sizeof szSection);
                                 AIT_SET_STR(&av->cfg_sec, line);
                         } else
                                 EDEBUG(7, "Ignore section '%s' ... not found ']'", line);
                         continue;
                 }
                 /* parse pair */
                 if (!(psAttr = strchr(line, '='))) {
                         AIT_SET_STR(&av->cfg_val, origin);
                         EDEBUG(7, "Ignore a/v '%s' ... not found '='", line);
                         continue;
                 } else {
                         *psAttr = 0;
                         psVal = psAttr + 1;
                         psAttr = line;
                 }
 
                 /* if exists, added section name to element */
                 if (*szSection) {
                         AIT_SET_STR(&av->cfg_sec, szSection);
                         AIT_KEY(&av->cfg_sec) = crcFletcher16(AIT_GET_LIKE(&av->cfg_sec, u_short*), 
                                         E_ALIGN(AIT_LEN(&av->cfg_sec) - 1, 2) / 2);
                 }
 
                 str_RTrim(psAttr);
                 str_LTrim(psVal);
                 if (!flg)
                         str_Unquot(psVal);
                 AIT_SET_STR(&av->cfg_val, psVal);
                 AIT_SET_STR(&av->cfg_attr, psAttr);
                 AIT_KEY(&av->cfg_attr) = crcFletcher16(AIT_GET_LIKE(&av->cfg_attr, u_short*), 
                                 E_ALIGN(AIT_LEN(&av->cfg_attr) - 1, 2) / 2);
 
                 CFG_RC_LOCK(cfg);
                 RB_INSERT(tagRC, cfg, av);
                 CFG_RC_UNLOCK(cfg);
 
                 /* read include file */
                 if (!flg && *AIT_GET_STR(&av->cfg_attr) == '%' && 
                                 !strcmp(AIT_GET_STR(&av->cfg_attr), "%include")) {
                         ff = fopen(AIT_GET_STR(&av->cfg_val), "r");
                         if (ff) {
                                 cfgReadConfig(ff, cfg);
                                 fclose(ff);
                         } else
                                 EDEBUG(7, "Error:: Can't open %s file", 
                                                 AIT_GET_STR(&av->cfg_val));
                 }
         }          }
        cfg->slh_first = prev;
         return 0;
 }  }
   
// cfgWrite() Write to file from config list/*
static inline int cfgWrite(FILE *f, sl_config * __restrict cfg, int whitespace) * cfgWriteConfig() - Write config from memory
  *
  * @f = File handle
  * @cfg = Config root
  * @whitespace = Additional whitespace characters to file
  * return: -1 error or 0 ok
  */
 int
 cfgWriteConfig(FILE *f, cfg_root_t * __restrict cfg, int whitespace)
 {  {
        struct tagPair *av;        struct tagCfg *av;
        time_t tim;        char line[BUFSIZ] = { 0 }, szSection[STRSIZ] = { [0 ... STRSIZ - 1] = 0 };
        char szTime[MAX_STR + 1]; 
        u_char szSection[MAX_STR + 1]; 
   
        bzero(szSection, MAX_STR + 1);        if (!f || !cfg) {
                cfg_SetErr(EINVAL, "Invalid parameter(s)");
        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;                  return -1;
         }          }
   
        InvertQueue(cfg);        CFG_RC_LOCK(cfg);
        for (av = cfg->slh_first; av; av = av->sle_next) {        RB_FOREACH(av, tagRC, cfg) {
                if (av->psSection && strcmp((char*) av->psSection, (char*) szSection)) {                /* empty lines or comment */
                        strlcpy((char*) szSection, (char*) av->psSection, MAX_STR + 1);                if (AIT_ISEMPTY(&av->cfg_attr)) {
                        if (!cfgDbg(f, "\n[%s]\n", av->psSection)) {                        if (AIT_ISEMPTY(&av->cfg_val))
                                LOGERR;                                continue;
                                return -1;                        strlcpy(line, AIT_GET_STR(&av->cfg_val), sizeof line);
                        }                        goto skip_sec;
                 }                  }
                 if (!av->psSection && *szSection) {  
                         bzero(szSection, MAX_STR + 1);  
                         if (!cfgDbg(f, "\n[]\n")) {  
                                 LOGERR;  
                                 return -1;  
                         }  
                 }  
   
                if (whitespace) {                /* section [] */
                        if (!cfgDbg(f, "%s = %s\n", av->psAttribute, av->psValue)) {                if (!AIT_ISEMPTY(&av->cfg_sec) && AIT_ADDR(&av->cfg_sec) && 
                                 strcmp(AIT_GET_STRZ(&av->cfg_sec), szSection)) {
                         strlcpy(szSection, AIT_GET_STR(&av->cfg_sec), sizeof szSection);
                         if (!cfg_Write(f, "\n[%s]\n", AIT_GET_STR(&av->cfg_sec))) {
                                 LOGERR;                                  LOGERR;
                                   CFG_RC_UNLOCK(cfg);
                                 return -1;                                  return -1;
                         }                          }
                } else {                } else if (AIT_ISEMPTY(&av->cfg_sec) && *szSection) {
                        if (!cfgDbg(f, "%s=%s\n", av->psAttribute, av->psValue)) {                        memset(szSection, 0, sizeof szSection);
                         if (!cfg_Write(f, "\n[]\n")) {
                                 LOGERR;                                  LOGERR;
                                   CFG_RC_UNLOCK(cfg);
                                 return -1;                                  return -1;
                         }                          }
                 }                  }
         }  
         InvertQueue(cfg);  
   
        bzero(szTime, MAX_STR + 1);                /* build line */
        time(&tim);                memset(line, 0, sizeof line);
        strftime(szTime, MAX_STR, "(UTC) %Y-%m-%d %H:%M:%S", gmtime(&tim));                if (!AIT_ISEMPTY(&av->cfg_attr) && AIT_TYPE(&av->cfg_attr) == string) {
        if (!cfgDbg(f, "\n#\n## Done. :: %s\n", szTime)) {                        strlcpy(line, AIT_GET_STRZ(&av->cfg_attr), sizeof line);
                LOGERR;                        if (whitespace)
                return -1;                                strlcat(line, " = ", sizeof line);
                         else
                                 strlcat(line, "=", sizeof line);
                 }
                 if (!AIT_ISEMPTY(&av->cfg_val) && AIT_TYPE(&av->cfg_val) == string)
                         strlcat(line, AIT_GET_STRZ(&av->cfg_val), sizeof line);
 skip_sec:
                 /* write */
                 if (!cfg_Write(f, "%s\n", line)) {
                         LOGERR;
                         CFG_RC_UNLOCK(cfg);
                         return -1;
                 }
         }          }
           CFG_RC_UNLOCK(cfg);
   
         return 0;          return 0;
 }  }
   
 // ---------------------------------------------------  
   
 /*  /*
 * ReadConfig() Read from file and add new item to config list * cfgWriteConfigRaw() - Write config from memory by list
 * @f = file resource *
 * @cfg = Head list element * @f = File handle
 * return: 0 ok; -1 error:: can`t allocate memory * @cfg = Config root
*/ * @whitespace = Additional whitespace characters to file
int ReadConfig(FILE *f, sl_config * __restrict cfg) * return: -1 error or 0 ok
  */
 int
 cfgWriteConfigRaw(FILE *f, cfg_root_t * __restrict cfg, int whitespace)
 {  {
        u_char szLine[MAX_STR + 1];        struct tagCfg *av, *nxt;
        u_char szSection[MAX_STR + 1], *psAttr, *psVal;        char line[BUFSIZ] = { 0 }, szSection[STRSIZ] = { [0 ... STRSIZ - 1] = 0 };
        int pos; 
        struct tagPair *av; 
   
        memset(szSection, 0, MAX_STR + 1);        if (!f || !cfg) {
        while (!feof(f)) {                cfg_SetErr(EINVAL, "Invalid parameter(s)");
                memset(szLine, 0, MAX_STR + 1);                return -1;
                fgets((char*) szLine, MAX_STR, f);        }
                io_TrimStr(szLine); 
#ifdef __DEBUG 
                cfgDbg(stdout, "DEBUG:: RAW |%s|\n", szLine); 
#endif 
   
                // End of config        CFG_RC_LOCK(cfg);
                if (*szLine == '.')        TAILQ_FOREACH_SAFE(av, cfg, cfg_next, nxt) {
                        break;                /* empty lines or comment */
                // Comment                if (AIT_ISEMPTY(&av->cfg_attr)) {
                if (*szLine == '#' || *szLine == ';' || !*szLine)                        if (AIT_ISEMPTY(&av->cfg_val))
                        continue;                                continue;
                        strlcpy(line, AIT_GET_STR(&av->cfg_val), sizeof line);
#ifdef __DEBUG                        goto skip_sec;
                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                /* section [] */
                pos = strchr((char*) szLine, '=') ? strchr((char*) szLine, '=') - (char*) szLine : 0;                if (!AIT_ISEMPTY(&av->cfg_sec) && AIT_ADDR(&av->cfg_sec) && 
                if (!pos) {                                strcmp(AIT_GET_STRZ(&av->cfg_sec), szSection)) {
#ifdef __DEBUG                        strlcpy(szSection, AIT_GET_STR(&av->cfg_sec), sizeof szSection);
                        cfgDbg(stdout, "WARNING:: Ignore a/v %s ... format error!\n", szLine);                        if (!cfg_Write(f, "\n[%s]\n", AIT_GET_STR(&av->cfg_sec))) {
#endif 
                        continue; 
                } else { 
                        av = malloc(sizeof(struct tagPair)); 
                        if (!av) { 
                                 LOGERR;                                  LOGERR;
                                   CFG_RC_UNLOCK(cfg);
                                 return -1;                                  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                } else if (AIT_ISEMPTY(&av->cfg_sec) && *szSection) {
                        if (*szSection) {                        memset(szSection, 0, sizeof szSection);
                                av->psSection = malloc(strlen((char*) szSection) + 1);                        if (!cfg_Write(f, "\n[]\n")) {
                                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; 
                        io_RTrimStr(psAttr); 
                        io_LTrimStr(psVal); 
                        io_UnquotStr(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;                                  LOGERR;
                                free(av->psSection);                                CFG_RC_UNLOCK(cfg);
                                free(av); 
                                 return -1;                                  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); 
                 }                  }
   
                   /* build line */
                   memset(line, 0, sizeof line);
                   if (!AIT_ISEMPTY(&av->cfg_attr) && AIT_TYPE(&av->cfg_attr) == string) {
                           strlcpy(line, AIT_GET_STRZ(&av->cfg_attr), sizeof line);
                           if (whitespace)
                                   strlcat(line, " = ", sizeof line);
                           else
                                   strlcat(line, "=", sizeof line);
                   }
                   if (!AIT_ISEMPTY(&av->cfg_val) && AIT_TYPE(&av->cfg_val) == string)
                           strlcat(line, AIT_GET_STRZ(&av->cfg_val), sizeof line);
   skip_sec:
                   /* write */
                   if (!cfg_Write(f, "%s\n", line)) {
                           LOGERR;
                           CFG_RC_UNLOCK(cfg);
                           return -1;
                   }
         }          }
           CFG_RC_UNLOCK(cfg);
   
         return 0;          return 0;
 }  }
   
 /*  /*
 * WriteConfig() Write to file from items in config list * cfgConcatConfig() - Concat two configs into one
 * @f = file resource *
 * @cfg = Head list element * @cfg = Config root
 * return: 0 ok; -1 error:: can`t write to file * @add_cfg = Concated config will be destroy after merge
*/ * return: -1 error or 0 ok
int WriteConfig(FILE *f, sl_config * __restrict cfg) */
 int
 cfgConcatConfig(cfg_root_t * __restrict cfg, cfg_root_t * __restrict add_cfg)
 {  {
        return cfgWrite(f, cfg, 1);        struct tagCfg *item;
} 
   
 /*  
  * 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)          if (!cfg || !add_cfg)
                 return -1;                  return -1;
   
        for (item = cfg->slh_first; item->sle_next; item = item->sle_next);        CFG_RC_LOCK(add_cfg);
        item->sle_next = add_cfg->slh_first;        CFG_RC_LOCK(cfg);
   
        add_cfg->slh_first = NULL;        /* concat lists & red-black trees */
         TAILQ_FOREACH(item, add_cfg, cfg_next) {
                 TAILQ_INSERT_TAIL(cfg, item, cfg_next);
                 RB_INSERT(tagRC, cfg, item);
         }
   
        return ret;        CFG_RC_UNLOCK(cfg);
 
         TAILQ_INIT(add_cfg);
         RB_INIT(add_cfg);
         CFG_RC_UNLOCK(add_cfg);
         pthread_mutex_destroy(&add_cfg->rc_mtx);
         return 0;
 }  }
   
 /*  /*
 * MergeConfig() Marge two list in one cfg and destroy add_cfg * cfgMergeConfig() - 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!) * @cfg = Config root of main list
 * return: 0 ok; -1 error:: can`t merge lists * @add_cfg = Merged config will be destroy after merge
*/ * return: -1 error or 0 ok
int MergeConfig(sl_config * __restrict cfg, sl_config * __restrict add_cfg) */
 int
 cfgMergeConfig(cfg_root_t * __restrict cfg, cfg_root_t * __restrict add_cfg)
 {  {
        struct tagPair *item, *merge, *add_next, *next = NULL;        struct tagCfg *item, *merge, *add_next, *next;
         int flg;          int flg;
   
         if (!cfg || !add_cfg)          if (!cfg || !add_cfg)
                 return -1;                  return -1;
   
        item = add_cfg->slh_first;        CFG_RC_LOCK(add_cfg);
        while (item) {        CFG_RC_LOCK(cfg);
                add_next = item->sle_next; 
   
                for (flg = 0, merge = cfg->slh_first, next = merge->sle_next; next;         /* merge lists */
                                merge = merge->sle_next, next = merge->sle_next) {        TAILQ_FOREACH_SAFE(item, add_cfg, cfg_next, add_next) {
                        if (!merge->psSection && !item->psSection) {                flg = 0;
                 TAILQ_FOREACH_SAFE(merge, cfg, cfg_next, next) {
                         if (AIT_ISEMPTY(&merge->cfg_sec) && AIT_ISEMPTY(&item->cfg_sec)) {
                                 flg = 1;                                  flg = 1;
                                 merge->sle_next = item;  
                                 item->sle_next = next;  
                                 break;                                  break;
                         }                          }
                        if (merge->psSection && item->psSection &&                         if (!AIT_ISEMPTY(&merge->cfg_sec) && !AIT_ISEMPTY(&item->cfg_sec) && 
                                        !strcmp((char*) merge->psSection, (char*) item->psSection)) {                                        AIT_ADDR(&merge->cfg_sec) && AIT_ADDR(&item->cfg_sec) &&
                                         !strcmp(AIT_GET_STR(&merge->cfg_sec), AIT_GET_STR(&item->cfg_sec))) {
                                 flg = 1;                                  flg = 1;
                                 merge->sle_next = item;  
                                 item->sle_next = next;  
                                 break;                                  break;
                         }                          }
                 }                  }
   
                if (!flg) {                if (!flg)
                        if (!merge->sle_next) {                        TAILQ_INSERT_TAIL(cfg, item, cfg_next);
                                merge->sle_next = item;                else
                                item->sle_next = NULL;                        TAILQ_INSERT_AFTER(cfg, merge, item, cfg_next);
                        } else                RB_INSERT(tagRC, cfg, item);
                                return -1;        }
 
         CFG_RC_UNLOCK(cfg);
 
         TAILQ_INIT(add_cfg);
         RB_INIT(add_cfg);
         CFG_RC_UNLOCK(add_cfg);
         pthread_mutex_destroy(&add_cfg->rc_mtx);
         return 0;
 }
 
 /*
  * cfgReadLines() - Read custom lines and add new item at config root
  *
  * @f = File resource
  * @delim = Custom delimiter, if =NULL default is '='
  * @end = Custom user end of file, if =NULL default is EOF
  * @cfg = Config root
  * return: -1 error or 0 ok
  */
 int
 cfgReadLines(FILE *f, const char *delim, const char *end, cfg_root_t * __restrict cfg)
 {
         char line[BUFSIZ];
         struct tagCfg *d, *av = NULL;
         char *p, *psSec, *psAttr, *psVal;
 
         if (!cfg)
                 return -1;
         if (!delim)
                 delim = ATR_LINES_DELIM;
 
         while (!feof(f)) {
                 psSec = psAttr = psVal = NULL;
                 memset(line, 0, sizeof line);
                 fgets(line, sizeof line - 1, f);
                 /* check for user end-of-file */
                 if (strspn(line, end))
                         break;
 
                 if (!(psAttr = strpbrk(line, "\r\n"))) {
                         /* skip line, too long */
                         continue;
                 } else {
                         *psAttr = 0;
                         str_Trim(line);
                         if (!*line)
                                 continue;
                 }                  }
   
                item = add_next;                if (!av_MakeExt(line, delim, &p, &psVal))
        }                        continue;
                 else {
                         str_RTrim(p);
                         str_LTrim(psVal);
                 }
                 if (!av_MakeExt(p, SEC_LINES_DELIM, &psSec, &psAttr))
                         psAttr = p;
   
        add_cfg->slh_first = NULL;                /* *NEW PAIR* alloc new pair element */
                 av = e_malloc(sizeof(struct tagCfg));
                 if (!av) {
                         LOGERR;
                         return -1;
                 } else
                         memset(av, 0, sizeof(struct tagCfg));
   
                   if (psSec) {
                           AIT_SET_STR(&av->cfg_sec, psSec);
                           AIT_KEY(&av->cfg_sec) = crcFletcher16(AIT_GET_LIKE(&av->cfg_sec, u_short*), 
                                           E_ALIGN(AIT_LEN(&av->cfg_sec) - 1, 2) / 2);
                   }
                   if (psVal)
                           AIT_SET_STR(&av->cfg_val, psVal);
                   AIT_SET_STR(&av->cfg_attr, psAttr);
                   AIT_KEY(&av->cfg_attr) = crcFletcher16(AIT_GET_LIKE(&av->cfg_attr, u_short*), 
                                   E_ALIGN(AIT_LEN(&av->cfg_attr) - 1, 2) / 2);
   
                   CFG_RC_LOCK(cfg);
                   /* find & delete duplicates */
                   if ((d = RB_FIND(tagRC, cfg, av))) {
                           RB_REMOVE(tagRC, cfg, d);
                           TAILQ_REMOVE(cfg, d, cfg_next);
   
                           AIT_FREE_VAL(&d->cfg_val);
                           AIT_FREE_VAL(&d->cfg_attr);
                           AIT_FREE_VAL(&d->cfg_sec);
                           e_free(d);
                   }
   
                   TAILQ_INSERT_TAIL(cfg, av, cfg_next);
                   RB_INSERT(tagRC, cfg, av);
                   CFG_RC_UNLOCK(cfg);
           }
   
         return 0;          return 0;
   }
   
   /*
    * cfgWriteLines() - Write custom lines and export data to variable
    *
    * @f = File resource
    * @delim = Custom delimiter, if =NULL default is '='
    * @eol = End of line string, if =NULL default is "\n"
    * @section = Export only section, if =NULL default is all
    * @cfg = Config root
    * return: =NULL error or !=NULL exported data, must be free after use with ait_freeVar()
    */
   ait_val_t *
   cfgWriteLines(FILE *f, const char *delim, const char *eol, const char *section, cfg_root_t * __restrict cfg)
   {
           ait_val_t *v = NULL;
           struct tagCfg *av;
   
           if (!cfg)
                   return NULL;
           if (!delim)
                   delim = ATR_LINES_DELIM;
           if (!eol)
                   eol = EOL_LINES_DELIM;
           if (!(v = ait_allocVar())) {
                   cfg_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
                   return NULL;
           } else
                   AIT_INIT_VAL2(v, string);
   
           TAILQ_FOREACH(av, cfg, cfg_next) {
                   if (section) {
                           if (!AIT_ISEMPTY(&av->cfg_sec) && *section)
                                   continue;
                           if (strcmp(section, AIT_GET_STRZ(&av->cfg_sec)))
                                   continue;
                   }
   
                   if (!AIT_ISEMPTY(&av->cfg_sec)) {
                           AIT_SET_STRCAT(v, AIT_GET_STR(&av->cfg_sec));
                           AIT_SET_STRCAT(v, SEC_LINES_DELIM);
                   }
                   if (!AIT_ISEMPTY(&av->cfg_attr)) {
                           AIT_SET_STRCAT(v, AIT_GET_STR(&av->cfg_attr));
                           AIT_SET_STRCAT(v, delim);
                   }
                   if (!AIT_ISEMPTY(&av->cfg_val))
                           AIT_SET_STRCAT(v, AIT_GET_STR(&av->cfg_val));
                   AIT_SET_STRCAT(v, eol);
           }
   
           if (f)
                   fputs(AIT_GET_STR(v), f);
           return v;
 }  }

Removed from v.1.6  
changed lines
  Added in v.1.19


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