Annotation of libaitcfg/src/parse.c, revision 1.21.6.1
1.2 misho 1: /*************************************************************************
2: * (C) 2008 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
3: * by Michael Pounov <misho@openbsd-bg.org>
4: *
5: * $Author: misho $
1.21.6.1! misho 6: * $Id: parse.c,v 1.21 2023/01/23 23:27:26 misho Exp $
1.2 misho 7: *
1.6 misho 8: **************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
1.21.6.1! misho 15: Copyright 2004 - 2025
1.6 misho 16: by Michael Pounov <misho@elwix.org>. All rights reserved.
17:
18: Redistribution and use in source and binary forms, with or without
19: modification, are permitted provided that the following conditions
20: are met:
21: 1. Redistributions of source code must retain the above copyright
22: notice, this list of conditions and the following disclaimer.
23: 2. Redistributions in binary form must reproduce the above copyright
24: notice, this list of conditions and the following disclaimer in the
25: documentation and/or other materials provided with the distribution.
26: 3. All advertising materials mentioning features or use of this software
27: must display the following acknowledgement:
28: This product includes software developed by Michael Pounov <misho@elwix.org>
29: ELWIX - Embedded LightWeight unIX and its contributors.
30: 4. Neither the name of AITNET nor the names of its contributors
31: may be used to endorse or promote products derived from this software
32: without specific prior written permission.
33:
34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: SUCH DAMAGE.
45: */
1.1 misho 46: #include "global.h"
47:
48:
1.7 misho 49: /*
50: * cfgReadConfig() - Read file and add new item at config root
51: *
52: * @f = File resource
53: * @cfg = Config root
54: * return: -1 error or 0 ok
55: */
1.9 misho 56: int
57: cfgReadConfig(FILE *f, cfg_root_t * __restrict cfg)
1.3 misho 58: {
1.21 misho 59: char line[BUFSIZ], origin[BUFSIZ], chkattr[STRSIZ];
1.7 misho 60: struct tagCfg *av = NULL;
61: int flg = 0;
62: char *psAttr, *psVal, szSection[STRSIZ] = { 0 };
1.18 misho 63: FILE *ff;
1.3 misho 64:
1.11 misho 65: if (!f || !cfg) {
66: cfg_SetErr(EINVAL, "Invalid parameter(s)");
67: return -1;
68: }
69:
1.7 misho 70: while (!feof(f)) {
71: memset(line, 0, sizeof line);
1.20 misho 72: if (!fgets(line, sizeof(line) - 1, f))
73: break;
1.7 misho 74: #ifdef SUPPORT_USER_EOF
75: /* check for user end-of-file */
76: if (line[0] == '.' && line[1] == '\n')
77: break;
78: #endif
79: if (!(psAttr = strpbrk(line, "\r\n"))) {
1.21.6.1! misho 80: if (feof(f) && strlen(line) > 0) {
! 81: /* last line without end of line */
! 82: strlcpy(origin, line, sizeof origin);
! 83: str_Trim(line);
! 84: } else {
! 85: /* skip line, too long */
! 86: continue;
! 87: }
1.7 misho 88: } else {
89: *psAttr = 0;
1.17 misho 90: strlcpy(origin, line, sizeof origin);
1.12 misho 91: str_Trim(line);
1.7 misho 92: }
1.3 misho 93:
1.7 misho 94: if (flg) {
95: /* continues line */
96: if (!av)
97: continue;
98: else
99: psAttr = line + strlen(line) - 1;
100: if (*psAttr == '\\')
101: *psAttr = 0;
102: else
103: flg = 0;
104: /* concat line to value */
105: AIT_SET_STRCAT(&av->cfg_val, line);
1.10 misho 106: if (!flg && AIT_ADDR(&av->cfg_val))
1.21 misho 107: av->cfg_quoted += str_Unquot((char*) AIT_GET_STR(&av->cfg_val));
1.18 misho 108:
109: /* read include file */
110: if (!flg && AIT_ADDR(&av->cfg_val) &&
111: *AIT_GET_STR(&av->cfg_attr) == '%' &&
112: !strcmp(AIT_GET_STR(&av->cfg_attr), "%include")) {
113: ff = fopen(AIT_GET_STR(&av->cfg_val), "r");
114: if (ff) {
115: cfgReadConfig(ff, cfg);
116: fclose(ff);
117: } else
1.21 misho 118: EDEBUG(ELWIX_DEBUG_LOG, "Error:: Can't open %s file",
1.18 misho 119: AIT_GET_STR(&av->cfg_val));
120: }
1.7 misho 121: continue;
122: }
1.3 misho 123:
1.21 misho 124: /* check for duplicated element */
125: if (*line != '#' && *line != ';' && *line != '/' && *line != '%' &&
126: (psAttr = strchr(line, '='))) {
127: strncpy(chkattr, line, psAttr - line);
128: chkattr[psAttr - line] = 0;
129: str_RTrim(chkattr);
130: if (cfg_findAttribute(cfg, szSection, chkattr))
131: cfg_unsetAttribute(cfg, szSection, chkattr);
132: }
133:
1.7 misho 134: /* *NEW PAIR* alloc new pair element */
1.12 misho 135: av = e_malloc(sizeof(struct tagCfg));
1.7 misho 136: if (!av) {
1.12 misho 137: cfg_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
1.7 misho 138: return -1;
139: } else {
140: memset(av, 0, sizeof(struct tagCfg));
141: CFG_RC_LOCK(cfg);
1.14 misho 142: TAILQ_INSERT_TAIL(cfg, av, cfg_next);
1.7 misho 143: CFG_RC_UNLOCK(cfg);
1.3 misho 144: }
1.7 misho 145:
1.18 misho 146: /* check for comment or empty line */
147: if (!*line || *line == '#' || *line == ';') {
148: AIT_SET_STR(&av->cfg_val, line);
149: continue;
150: }
151:
1.7 misho 152: /* check for continues line */
1.8 misho 153: psAttr = line + (*line ? strlen(line) : 1) - 1;
1.7 misho 154: if (*psAttr == '\\') {
155: *psAttr = 0;
156: flg = 1;
1.3 misho 157: }
158:
1.7 misho 159: /* section */
160: if (*line == '[') {
161: psAttr = line + strlen(line) - 1;
162: if (*psAttr == ']') {
163: *psAttr = 0;
164: flg = 0;
165: strlcpy(szSection, line + 1, sizeof szSection);
1.13 misho 166: AIT_SET_STR(&av->cfg_sec, line);
1.7 misho 167: } else
1.21 misho 168: EDEBUG(ELWIX_DEBUG_LOG, "Ignore section '%s' ... not found ']'", line);
1.7 misho 169: continue;
170: }
171: /* parse pair */
172: if (!(psAttr = strchr(line, '='))) {
1.17 misho 173: AIT_SET_STR(&av->cfg_val, origin);
1.21 misho 174: EDEBUG(ELWIX_DEBUG_LOG, "Ignore a/v '%s' ... not found '='", line);
1.7 misho 175: continue;
1.3 misho 176: } else {
1.7 misho 177: *psAttr = 0;
178: psVal = psAttr + 1;
179: psAttr = line;
180: }
181:
182: /* if exists, added section name to element */
183: if (*szSection) {
184: AIT_SET_STR(&av->cfg_sec, szSection);
185: AIT_KEY(&av->cfg_sec) = crcFletcher16(AIT_GET_LIKE(&av->cfg_sec, u_short*),
1.12 misho 186: E_ALIGN(AIT_LEN(&av->cfg_sec) - 1, 2) / 2);
1.3 misho 187: }
188:
1.12 misho 189: str_RTrim(psAttr);
190: str_LTrim(psVal);
1.7 misho 191: if (!flg)
1.21 misho 192: av->cfg_quoted += str_Unquot(psVal);
1.7 misho 193: AIT_SET_STR(&av->cfg_val, psVal);
194: AIT_SET_STR(&av->cfg_attr, psAttr);
195: AIT_KEY(&av->cfg_attr) = crcFletcher16(AIT_GET_LIKE(&av->cfg_attr, u_short*),
1.12 misho 196: E_ALIGN(AIT_LEN(&av->cfg_attr) - 1, 2) / 2);
1.7 misho 197:
198: CFG_RC_LOCK(cfg);
199: RB_INSERT(tagRC, cfg, av);
200: CFG_RC_UNLOCK(cfg);
1.18 misho 201:
202: /* read include file */
203: if (!flg && *AIT_GET_STR(&av->cfg_attr) == '%' &&
204: !strcmp(AIT_GET_STR(&av->cfg_attr), "%include")) {
205: ff = fopen(AIT_GET_STR(&av->cfg_val), "r");
206: if (ff) {
207: cfgReadConfig(ff, cfg);
208: fclose(ff);
209: } else
1.21 misho 210: EDEBUG(ELWIX_DEBUG_LOG, "Error:: Can't open %s file",
1.18 misho 211: AIT_GET_STR(&av->cfg_val));
212: }
1.3 misho 213: }
214:
215: return 0;
216: }
217:
1.1 misho 218: /*
1.7 misho 219: * cfgWriteConfig() - Write config from memory
220: *
221: * @f = File handle
222: * @cfg = Config root
223: * @whitespace = Additional whitespace characters to file
224: * return: -1 error or 0 ok
225: */
226: int
227: cfgWriteConfig(FILE *f, cfg_root_t * __restrict cfg, int whitespace)
1.1 misho 228: {
1.7 misho 229: struct tagCfg *av;
1.13 misho 230: char line[BUFSIZ] = { 0 }, szSection[STRSIZ] = { [0 ... STRSIZ - 1] = 0 };
1.1 misho 231:
1.11 misho 232: if (!f || !cfg) {
233: cfg_SetErr(EINVAL, "Invalid parameter(s)");
234: return -1;
235: }
236:
1.7 misho 237: CFG_RC_LOCK(cfg);
1.14 misho 238: RB_FOREACH(av, tagRC, cfg) {
1.13 misho 239: /* empty lines or comment */
240: if (AIT_ISEMPTY(&av->cfg_attr)) {
241: if (AIT_ISEMPTY(&av->cfg_val))
242: continue;
243: strlcpy(line, AIT_GET_STR(&av->cfg_val), sizeof line);
244: goto skip_sec;
245: }
246:
247: /* section [] */
1.10 misho 248: if (!AIT_ISEMPTY(&av->cfg_sec) && AIT_ADDR(&av->cfg_sec) &&
1.14 misho 249: strcmp(AIT_GET_STRZ(&av->cfg_sec), szSection)) {
1.7 misho 250: strlcpy(szSection, AIT_GET_STR(&av->cfg_sec), sizeof szSection);
1.21 misho 251: if (!cfg_Write(f, "[%s]\n", AIT_GET_STR(&av->cfg_sec))) {
1.7 misho 252: LOGERR;
253: CFG_RC_UNLOCK(cfg);
254: return -1;
1.1 misho 255: }
1.13 misho 256: } else if (AIT_ISEMPTY(&av->cfg_sec) && *szSection) {
1.7 misho 257: memset(szSection, 0, sizeof szSection);
1.21 misho 258: if (!cfg_Write(f, "[]\n")) {
1.1 misho 259: LOGERR;
1.7 misho 260: CFG_RC_UNLOCK(cfg);
1.1 misho 261: return -1;
262: }
1.7 misho 263: }
264:
265: /* build line */
266: memset(line, 0, sizeof line);
1.11 misho 267: if (!AIT_ISEMPTY(&av->cfg_attr) && AIT_TYPE(&av->cfg_attr) == string) {
268: strlcpy(line, AIT_GET_STRZ(&av->cfg_attr), sizeof line);
1.7 misho 269: if (whitespace)
270: strlcat(line, " = ", sizeof line);
271: else
272: strlcat(line, "=", sizeof line);
273: }
1.21 misho 274: if (!AIT_ISEMPTY(&av->cfg_val) && AIT_TYPE(&av->cfg_val) == string) {
275: if (av->cfg_quoted)
276: strlcat(line, "\"", sizeof line);
1.11 misho 277: strlcat(line, AIT_GET_STRZ(&av->cfg_val), sizeof line);
1.21 misho 278: if (av->cfg_quoted)
279: strlcat(line, "\"", sizeof line);
280: }
1.13 misho 281: skip_sec:
1.7 misho 282: /* write */
283: if (!cfg_Write(f, "%s\n", line)) {
284: LOGERR;
285: CFG_RC_UNLOCK(cfg);
286: return -1;
1.1 misho 287: }
288: }
1.7 misho 289: CFG_RC_UNLOCK(cfg);
290:
1.1 misho 291: return 0;
292: }
293:
294: /*
1.19 misho 295: * cfgWriteConfigRaw() - Write config from memory by list
296: *
297: * @f = File handle
298: * @cfg = Config root
299: * @whitespace = Additional whitespace characters to file
300: * return: -1 error or 0 ok
301: */
302: int
303: cfgWriteConfigRaw(FILE *f, cfg_root_t * __restrict cfg, int whitespace)
304: {
305: struct tagCfg *av, *nxt;
306: char line[BUFSIZ] = { 0 }, szSection[STRSIZ] = { [0 ... STRSIZ - 1] = 0 };
307:
308: if (!f || !cfg) {
309: cfg_SetErr(EINVAL, "Invalid parameter(s)");
310: return -1;
311: }
312:
313: CFG_RC_LOCK(cfg);
314: TAILQ_FOREACH_SAFE(av, cfg, cfg_next, nxt) {
315: /* empty lines or comment */
316: if (AIT_ISEMPTY(&av->cfg_attr)) {
317: if (AIT_ISEMPTY(&av->cfg_val))
318: continue;
319: strlcpy(line, AIT_GET_STR(&av->cfg_val), sizeof line);
320: goto skip_sec;
321: }
322:
323: /* section [] */
324: if (!AIT_ISEMPTY(&av->cfg_sec) && AIT_ADDR(&av->cfg_sec) &&
325: strcmp(AIT_GET_STRZ(&av->cfg_sec), szSection)) {
326: strlcpy(szSection, AIT_GET_STR(&av->cfg_sec), sizeof szSection);
1.21 misho 327: if (!cfg_Write(f, "[%s]\n", AIT_GET_STR(&av->cfg_sec))) {
1.19 misho 328: LOGERR;
329: CFG_RC_UNLOCK(cfg);
330: return -1;
331: }
332: } else if (AIT_ISEMPTY(&av->cfg_sec) && *szSection) {
333: memset(szSection, 0, sizeof szSection);
1.21 misho 334: if (!cfg_Write(f, "[]\n")) {
1.19 misho 335: LOGERR;
336: CFG_RC_UNLOCK(cfg);
337: return -1;
338: }
339: }
340:
341: /* build line */
342: memset(line, 0, sizeof line);
343: if (!AIT_ISEMPTY(&av->cfg_attr) && AIT_TYPE(&av->cfg_attr) == string) {
344: strlcpy(line, AIT_GET_STRZ(&av->cfg_attr), sizeof line);
345: if (whitespace)
346: strlcat(line, " = ", sizeof line);
347: else
348: strlcat(line, "=", sizeof line);
349: }
1.21 misho 350: if (!AIT_ISEMPTY(&av->cfg_val) && AIT_TYPE(&av->cfg_val) == string) {
351: if (av->cfg_quoted)
352: strlcat(line, "\"", sizeof line);
1.19 misho 353: strlcat(line, AIT_GET_STRZ(&av->cfg_val), sizeof line);
1.21 misho 354: if (av->cfg_quoted)
355: strlcat(line, "\"", sizeof line);
356: }
1.19 misho 357: skip_sec:
358: /* write */
359: if (!cfg_Write(f, "%s\n", line)) {
360: LOGERR;
361: CFG_RC_UNLOCK(cfg);
362: return -1;
363: }
364: }
365: CFG_RC_UNLOCK(cfg);
366:
367: return 0;
368: }
369: /*
1.7 misho 370: * cfgConcatConfig() - Concat two configs into one
371: *
372: * @cfg = Config root
373: * @add_cfg = Concated config will be destroy after merge
374: * return: -1 error or 0 ok
375: */
376: int
377: cfgConcatConfig(cfg_root_t * __restrict cfg, cfg_root_t * __restrict add_cfg)
1.1 misho 378: {
1.7 misho 379: struct tagCfg *item;
1.3 misho 380:
1.7 misho 381: if (!cfg || !add_cfg)
382: return -1;
1.3 misho 383:
1.7 misho 384: CFG_RC_LOCK(add_cfg);
385: CFG_RC_LOCK(cfg);
1.3 misho 386:
1.14 misho 387: /* concat lists & red-black trees */
388: TAILQ_FOREACH(item, add_cfg, cfg_next) {
389: TAILQ_INSERT_TAIL(cfg, item, cfg_next);
1.7 misho 390: RB_INSERT(tagRC, cfg, item);
1.14 misho 391: }
1.3 misho 392:
1.7 misho 393: CFG_RC_UNLOCK(cfg);
1.3 misho 394:
1.14 misho 395: TAILQ_INIT(add_cfg);
396: RB_INIT(add_cfg);
1.11 misho 397: CFG_RC_UNLOCK(add_cfg);
1.7 misho 398: pthread_mutex_destroy(&add_cfg->rc_mtx);
399: return 0;
1.3 misho 400: }
1.1 misho 401:
1.3 misho 402: /*
1.7 misho 403: * cfgMergeConfig() - Marge two list in one cfg and destroy add_cfg
404: *
405: * @cfg = Config root of main list
406: * @add_cfg = Merged config will be destroy after merge
407: * return: -1 error or 0 ok
408: */
409: int
410: cfgMergeConfig(cfg_root_t * __restrict cfg, cfg_root_t * __restrict add_cfg)
1.3 misho 411: {
1.10 misho 412: struct tagCfg *item, *merge, *add_next, *next;
1.3 misho 413: int flg;
1.1 misho 414:
1.3 misho 415: if (!cfg || !add_cfg)
1.1 misho 416: return -1;
417:
1.7 misho 418: CFG_RC_LOCK(add_cfg);
419: CFG_RC_LOCK(cfg);
1.10 misho 420:
421: /* merge lists */
1.14 misho 422: TAILQ_FOREACH_SAFE(item, add_cfg, cfg_next, add_next) {
1.7 misho 423: flg = 0;
1.14 misho 424: TAILQ_FOREACH_SAFE(merge, cfg, cfg_next, next) {
1.7 misho 425: if (AIT_ISEMPTY(&merge->cfg_sec) && AIT_ISEMPTY(&item->cfg_sec)) {
1.3 misho 426: flg = 1;
427: break;
428: }
1.7 misho 429: if (!AIT_ISEMPTY(&merge->cfg_sec) && !AIT_ISEMPTY(&item->cfg_sec) &&
1.10 misho 430: AIT_ADDR(&merge->cfg_sec) && AIT_ADDR(&item->cfg_sec) &&
1.7 misho 431: !strcmp(AIT_GET_STR(&merge->cfg_sec), AIT_GET_STR(&item->cfg_sec))) {
1.21 misho 432: flg = -1;
1.3 misho 433: break;
1.1 misho 434: }
435: }
1.3 misho 436:
1.21 misho 437: switch (flg) {
438: case -1:
439: continue; /* skip duplicated element */
440: case 1:
441: TAILQ_INSERT_AFTER(cfg, merge, item, cfg_next);
442: break;
443: case 0:
444: TAILQ_INSERT_TAIL(cfg, item, cfg_next);
445: break;
446: }
1.10 misho 447: RB_INSERT(tagRC, cfg, item);
1.1 misho 448: }
1.10 misho 449:
1.7 misho 450: CFG_RC_UNLOCK(cfg);
1.1 misho 451:
1.14 misho 452: TAILQ_INIT(add_cfg);
453: RB_INIT(add_cfg);
1.11 misho 454: CFG_RC_UNLOCK(add_cfg);
1.7 misho 455: pthread_mutex_destroy(&add_cfg->rc_mtx);
1.1 misho 456: return 0;
457: }
1.9 misho 458:
459: /*
460: * cfgReadLines() - Read custom lines and add new item at config root
461: *
462: * @f = File resource
463: * @delim = Custom delimiter, if =NULL default is '='
464: * @end = Custom user end of file, if =NULL default is EOF
465: * @cfg = Config root
466: * return: -1 error or 0 ok
467: */
468: int
469: cfgReadLines(FILE *f, const char *delim, const char *end, cfg_root_t * __restrict cfg)
470: {
471: char line[BUFSIZ];
472: struct tagCfg *d, *av = NULL;
1.11 misho 473: char *p, *psSec, *psAttr, *psVal;
474:
475: if (!cfg)
476: return -1;
477: if (!delim)
478: delim = ATR_LINES_DELIM;
1.9 misho 479:
480: while (!feof(f)) {
1.11 misho 481: psSec = psAttr = psVal = NULL;
1.9 misho 482: memset(line, 0, sizeof line);
1.20 misho 483: if (!fgets(line, sizeof(line) - 1, f))
484: break;
1.9 misho 485: /* check for user end-of-file */
486: if (strspn(line, end))
487: break;
488:
489: if (!(psAttr = strpbrk(line, "\r\n"))) {
490: /* skip line, too long */
491: continue;
492: } else {
493: *psAttr = 0;
1.12 misho 494: str_Trim(line);
1.9 misho 495: if (!*line)
496: continue;
497: }
498:
1.12 misho 499: if (!av_MakeExt(line, delim, &p, &psVal))
1.9 misho 500: continue;
501: else {
1.12 misho 502: str_RTrim(p);
503: str_LTrim(psVal);
1.9 misho 504: }
1.12 misho 505: if (!av_MakeExt(p, SEC_LINES_DELIM, &psSec, &psAttr))
1.11 misho 506: psAttr = p;
1.9 misho 507:
1.21 misho 508: /* check for duplicated element */
509: if (psAttr && cfg_findAttribute(cfg, psSec, psAttr))
510: cfg_unsetAttribute(cfg, psSec, psAttr);
511:
1.9 misho 512: /* *NEW PAIR* alloc new pair element */
1.12 misho 513: av = e_malloc(sizeof(struct tagCfg));
1.9 misho 514: if (!av) {
515: LOGERR;
516: return -1;
517: } else
518: memset(av, 0, sizeof(struct tagCfg));
519:
1.11 misho 520: if (psSec) {
521: AIT_SET_STR(&av->cfg_sec, psSec);
522: AIT_KEY(&av->cfg_sec) = crcFletcher16(AIT_GET_LIKE(&av->cfg_sec, u_short*),
1.12 misho 523: E_ALIGN(AIT_LEN(&av->cfg_sec) - 1, 2) / 2);
1.11 misho 524: }
1.21 misho 525: if (psVal) {
526: av->cfg_quoted = str_Unquot(psVal);
1.9 misho 527: AIT_SET_STR(&av->cfg_val, psVal);
1.21 misho 528: }
1.9 misho 529: AIT_SET_STR(&av->cfg_attr, psAttr);
530: AIT_KEY(&av->cfg_attr) = crcFletcher16(AIT_GET_LIKE(&av->cfg_attr, u_short*),
1.12 misho 531: E_ALIGN(AIT_LEN(&av->cfg_attr) - 1, 2) / 2);
1.9 misho 532:
533: CFG_RC_LOCK(cfg);
534: /* find & delete duplicates */
535: if ((d = RB_FIND(tagRC, cfg, av))) {
536: RB_REMOVE(tagRC, cfg, d);
1.14 misho 537: TAILQ_REMOVE(cfg, d, cfg_next);
1.9 misho 538:
539: AIT_FREE_VAL(&d->cfg_val);
540: AIT_FREE_VAL(&d->cfg_attr);
541: AIT_FREE_VAL(&d->cfg_sec);
1.12 misho 542: e_free(d);
1.9 misho 543: }
544:
1.14 misho 545: TAILQ_INSERT_TAIL(cfg, av, cfg_next);
1.9 misho 546: RB_INSERT(tagRC, cfg, av);
547: CFG_RC_UNLOCK(cfg);
548: }
549:
550: return 0;
551: }
552:
1.11 misho 553: /*
554: * cfgWriteLines() - Write custom lines and export data to variable
555: *
556: * @f = File resource
557: * @delim = Custom delimiter, if =NULL default is '='
558: * @eol = End of line string, if =NULL default is "\n"
559: * @section = Export only section, if =NULL default is all
560: * @cfg = Config root
1.12 misho 561: * return: =NULL error or !=NULL exported data, must be free after use with ait_freeVar()
1.11 misho 562: */
563: ait_val_t *
564: cfgWriteLines(FILE *f, const char *delim, const char *eol, const char *section, cfg_root_t * __restrict cfg)
565: {
566: ait_val_t *v = NULL;
567: struct tagCfg *av;
568:
569: if (!cfg)
570: return NULL;
571: if (!delim)
572: delim = ATR_LINES_DELIM;
573: if (!eol)
574: eol = EOL_LINES_DELIM;
1.12 misho 575: if (!(v = ait_allocVar())) {
576: cfg_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
1.11 misho 577: return NULL;
578: } else
579: AIT_INIT_VAL2(v, string);
580:
1.14 misho 581: TAILQ_FOREACH(av, cfg, cfg_next) {
1.11 misho 582: if (section) {
583: if (!AIT_ISEMPTY(&av->cfg_sec) && *section)
584: continue;
1.14 misho 585: if (strcmp(section, AIT_GET_STRZ(&av->cfg_sec)))
1.11 misho 586: continue;
587: }
588:
589: if (!AIT_ISEMPTY(&av->cfg_sec)) {
590: AIT_SET_STRCAT(v, AIT_GET_STR(&av->cfg_sec));
591: AIT_SET_STRCAT(v, SEC_LINES_DELIM);
592: }
1.16 misho 593: if (!AIT_ISEMPTY(&av->cfg_attr)) {
594: AIT_SET_STRCAT(v, AIT_GET_STR(&av->cfg_attr));
595: AIT_SET_STRCAT(v, delim);
596: }
1.21 misho 597: if (!AIT_ISEMPTY(&av->cfg_val)) {
598: if (av->cfg_quoted)
599: AIT_SET_STRCAT(v, "\"");
1.11 misho 600: AIT_SET_STRCAT(v, AIT_GET_STR(&av->cfg_val));
1.21 misho 601: if (av->cfg_quoted)
602: AIT_SET_STRCAT(v, "\"");
603: }
1.11 misho 604: AIT_SET_STRCAT(v, eol);
605: }
606:
607: if (f)
608: fputs(AIT_GET_STR(v), f);
609: return v;
610: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>