1: /*************************************************************************
2: * (C) 2008 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
3: * by Michael Pounov <misho@openbsd-bg.org>
4: *
5: * $Author: misho $
6: * $Id: parse.c,v 1.6.4.1 2012/04/02 14:39:02 misho Exp $
7: *
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:
15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
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: */
46: #include "global.h"
47: #include "aitcfg.h"
48:
49:
50: #if 0
51: // cfgDbg() Debug/Log operation
52: static inline int cfgDbg(FILE *f, char *fmt, ...)
53: {
54: int ret = 0;
55: va_list lst;
56:
57: va_start(lst, fmt);
58: ret = vfprintf(f, fmt, lst);
59: va_end(lst);
60:
61: return ret;
62: }
63:
64: /*
65: * InvertQueue() InvertQueue order //{cfg} list of elements for revert
66: * @cfg = Head list element for revert
67: */
68: static inline void InvertQueue(sl_config * __restrict cfg)
69: {
70: struct tagPair *item, *next, *prev = NULL;
71:
72: for (item = cfg->slh_first; item; item = next) {
73: next = item->sle_next;
74: item->sle_next = prev;
75: prev = item;
76: }
77: cfg->slh_first = prev;
78: }
79:
80: // cfgWrite() Write to file from config list
81: static inline int cfgWrite(FILE *f, sl_config * __restrict cfg, int whitespace)
82: {
83: struct tagPair *av;
84: time_t tim;
85: char szTime[MAX_STR + 1];
86: u_char szSection[MAX_STR + 1];
87:
88: bzero(szSection, MAX_STR + 1);
89:
90: bzero(szTime, MAX_STR + 1);
91: time(&tim);
92: strftime(szTime, MAX_STR, "(UTC) %Y-%m-%d %H:%M:%S", gmtime(&tim));
93: if (!cfgDbg(f, "## Write Config :: %s\n#\n", szTime)) {
94: LOGERR;
95: return -1;
96: }
97:
98: InvertQueue(cfg);
99: for (av = cfg->slh_first; av; av = av->sle_next) {
100: if (av->psSection && strcmp((char*) av->psSection, (char*) szSection)) {
101: strlcpy((char*) szSection, (char*) av->psSection, MAX_STR + 1);
102: if (!cfgDbg(f, "\n[%s]\n", av->psSection)) {
103: LOGERR;
104: return -1;
105: }
106: }
107: if (!av->psSection && *szSection) {
108: bzero(szSection, MAX_STR + 1);
109: if (!cfgDbg(f, "\n[]\n")) {
110: LOGERR;
111: return -1;
112: }
113: }
114:
115: if (whitespace) {
116: if (!cfgDbg(f, "%s = %s\n", av->psAttribute, av->psValue)) {
117: LOGERR;
118: return -1;
119: }
120: } else {
121: if (!cfgDbg(f, "%s=%s\n", av->psAttribute, av->psValue)) {
122: LOGERR;
123: return -1;
124: }
125: }
126: }
127: InvertQueue(cfg);
128:
129: bzero(szTime, MAX_STR + 1);
130: time(&tim);
131: strftime(szTime, MAX_STR, "(UTC) %Y-%m-%d %H:%M:%S", gmtime(&tim));
132: if (!cfgDbg(f, "\n#\n## Done. :: %s\n", szTime)) {
133: LOGERR;
134: return -1;
135: }
136:
137: return 0;
138: }
139:
140: // ---------------------------------------------------
141: #endif
142:
143: /*
144: * cfgReadConfig() - Read file and add new item at config root
145: *
146: * @f = File resource
147: * @cfg = Config root
148: * return: -1 error or 0 ok
149: */
150: int cfgReadConfig(FILE *f, cfg_root_t * __restrict cfg)
151: {
152: char line[BUFSIZ];
153: struct tagCfg *av = NULL;
154: int flg = 0;
155: char *psAttr, *psVal, szSection[STRSIZ] = { 0 };
156:
157: while (!feof(f)) {
158: memset(line, 0, sizeof line);
159: fgets(line, sizeof line - 1, f);
160: #ifdef SUPPORT_USER_EOF
161: /* check for user end-of-file */
162: if (line[0] == '.' && line[1] == '\n')
163: break;
164: #endif
165: if (!(psAttr = strpbrk(line, "\r\n"))) {
166: /* skip line, too long */
167: continue;
168: } else {
169: *psAttr = 0;
170: io_TrimStr(line);
171: }
172:
173: if (flg) {
174: /* continues line */
175: if (!av)
176: continue;
177: else
178: psAttr = line + strlen(line) - 1;
179: if (*psAttr == '\\')
180: *psAttr = 0;
181: else
182: flg = 0;
183: /* concat line to value */
184: AIT_SET_STRCAT(&av->cfg_val, line);
185: if (!flg)
186: io_UnquotStr((char*) AIT_GET_STR(&av->cfg_val));
187: continue;
188: }
189:
190: /* *NEW PAIR* alloc new pair element */
191: av = malloc(sizeof(struct tagCfg));
192: if (!av) {
193: LOGERR;
194: return -1;
195: } else {
196: memset(av, 0, sizeof(struct tagCfg));
197: CFG_RC_LOCK(cfg);
198: SLIST_INSERT_HEAD(cfg, av, cfg_next);
199: CFG_RC_UNLOCK(cfg);
200: }
201:
202: /* check for continues line */
203: psAttr = line + strlen(line) - 1;
204: if (*psAttr == '\\') {
205: *psAttr = 0;
206: flg = 1;
207: }
208:
209: /* check for comment or empty line */
210: if (!*line || *line == '#' || *line == ';') {
211: AIT_SET_STR(&av->cfg_val, line);
212: continue;
213: }
214: /* section */
215: if (*line == '[') {
216: AIT_SET_STR(&av->cfg_val, line);
217: psAttr = line + strlen(line) - 1;
218: if (*psAttr == ']') {
219: *psAttr = 0;
220: flg = 0;
221: strlcpy(szSection, line + 1, sizeof szSection);
222: } else
223: ioDEBUG(7, "Ignore section '%s' ... not found ']'", line);
224: continue;
225: }
226: /* parse pair */
227: if (!(psAttr = strchr(line, '='))) {
228: AIT_SET_STR(&av->cfg_val, line);
229: ioDEBUG(7, "Ignore a/v '%s' ... not found '='", line);
230: continue;
231: } else {
232: *psAttr = 0;
233: psVal = psAttr + 1;
234: psAttr = line;
235: }
236:
237: /* if exists, added section name to element */
238: if (*szSection) {
239: AIT_SET_STR(&av->cfg_sec, szSection);
240: AIT_KEY(&av->cfg_sec) = crcFletcher16(AIT_GET_LIKE(&av->cfg_sec, u_short*),
241: io_align(AIT_LEN(&av->cfg_sec) - 1, 1) / 2);
242: }
243:
244: io_RTrimStr(psAttr);
245: io_LTrimStr(psVal);
246: if (!flg)
247: io_UnquotStr(psVal);
248: AIT_SET_STR(&av->cfg_val, psVal);
249: AIT_SET_STR(&av->cfg_attr, psAttr);
250: AIT_KEY(&av->cfg_attr) = crcFletcher16(AIT_GET_LIKE(&av->cfg_attr, u_short*),
251: io_align(AIT_LEN(&av->cfg_attr) - 1, 1) / 2);
252:
253: CFG_RC_LOCK(cfg);
254: RB_INSERT(tagRC, cfg, av);
255: CFG_RC_UNLOCK(cfg);
256: }
257:
258: return 0;
259: }
260:
261: #if 0
262: /*
263: * WriteConfig() Write to file from items in config list
264: * @f = file resource
265: * @cfg = Head list element
266: * return: 0 ok; -1 error:: can`t write to file
267: */
268: int WriteConfig(FILE *f, sl_config * __restrict cfg)
269: {
270: return cfgWrite(f, cfg, 1);
271: }
272:
273: /*
274: * cfg_WriteConfig() Write to file from items in config list without whitespaces!
275: * @f = file resource
276: * @cfg = Head list element
277: * return: 0 ok; -1 error:: can`t write to file
278: */
279: int cfg_WriteConfig(FILE *f, sl_config * __restrict cfg)
280: {
281: return cfgWrite(f, cfg, 0);
282: }
283:
284: /*
285: * ConcatConfig() Concat two list in one
286: * @cfg = Head list element of main list
287: * @add_cfg = Head list element of added list
288: * return: 0 ok; -1 error:: can`t concat lists
289: */
290: int ConcatConfig(sl_config * __restrict cfg, sl_config * __restrict add_cfg)
291: {
292: struct tagPair *item;
293: int ret = 0;
294:
295: if (!cfg || !add_cfg)
296: return -1;
297:
298: for (item = cfg->slh_first; item->sle_next; item = item->sle_next);
299: item->sle_next = add_cfg->slh_first;
300:
301: add_cfg->slh_first = NULL;
302:
303: return ret;
304: }
305:
306: /*
307: * MergeConfig() Marge two list in one cfg and destroy add_cfg
308: * @cfg = Head list element of main list
309: * @add_cfg = Head list element of merged list (destroy after all!)
310: * return: 0 ok; -1 error:: can`t merge lists
311: */
312: int MergeConfig(sl_config * __restrict cfg, sl_config * __restrict add_cfg)
313: {
314: struct tagPair *item, *merge, *add_next, *next = NULL;
315: int flg;
316:
317: if (!cfg || !add_cfg)
318: return -1;
319:
320: item = add_cfg->slh_first;
321: while (item) {
322: add_next = item->sle_next;
323:
324: for (flg = 0, merge = cfg->slh_first, next = merge->sle_next; next;
325: merge = merge->sle_next, next = merge->sle_next) {
326: if (!merge->psSection && !item->psSection) {
327: flg = 1;
328: merge->sle_next = item;
329: item->sle_next = next;
330: break;
331: }
332: if (merge->psSection && item->psSection &&
333: !strcmp((char*) merge->psSection, (char*) item->psSection)) {
334: flg = 1;
335: merge->sle_next = item;
336: item->sle_next = next;
337: break;
338: }
339: }
340:
341: if (!flg) {
342: if (!merge->sle_next) {
343: merge->sle_next = item;
344: item->sle_next = NULL;
345: } else
346: return -1;
347: }
348:
349: item = add_next;
350: }
351:
352: add_cfg->slh_first = NULL;
353:
354: return 0;
355: }
356: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>