Annotation of libaitcfg/src/queue.c, revision 1.21
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 ! misho 6: * $Id: queue.c,v 1.20.4.1 2025/10/09 16:40:02 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.20 misho 15: Copyright 2004 - 2024
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: static inline struct tagCfg *
50: _selectAttribute(cfg_root_t * __restrict cfg, const char *csSec, const char *csAttr)
1.1 misho 51: {
1.19 misho 52: struct tagCfg fav, *c, *n;
1.1 misho 53:
54: if (!cfg)
55: return NULL;
1.7 misho 56: else
57: memset(&fav, 0, sizeof fav);
1.1 misho 58:
1.7 misho 59: if (csSec && *csSec)
60: AIT_KEY(&fav.cfg_sec) = crcFletcher16((u_short*) csSec,
1.12 misho 61: E_ALIGN(strlen(csSec), 2) / 2);
1.7 misho 62: if (csAttr)
63: AIT_KEY(&fav.cfg_attr) = crcFletcher16((u_short*) csAttr,
1.12 misho 64: E_ALIGN(strlen(csAttr), 2) / 2);
1.7 misho 65:
1.19 misho 66: if (!csAttr) {
67: c = RB_NFIND(tagRC, cfg, &fav);
68: if (!c)
69: return NULL; /* not found */
70: if (csSec && !AIT_ISEMPTY(&c->cfg_sec) &&
71: strcmp(csSec, AIT_GET_STR(&c->cfg_sec)))
72: TAILQ_FOREACH_SAFE(c, cfg, cfg_next, n) {
73: if (!AIT_ISEMPTY(&c->cfg_sec) &&
74: !strcmp(csSec, AIT_GET_STR(&c->cfg_sec)))
75: break;
76: }
77: return c;
78: } else {
1.10 misho 79: c = RB_FIND(tagRC, cfg, &fav);
80: if (!c)
81: return NULL; /* not found */
1.19 misho 82: /* if cannot find right section */
83: if (csSec && !AIT_ISEMPTY(&c->cfg_sec) &&
84: strcmp(csSec, AIT_GET_STR(&c->cfg_sec))) {
85: TAILQ_FOREACH_SAFE(c, cfg, cfg_next, n) {
86: if (!AIT_ISEMPTY(&c->cfg_sec) && csAttr &&
87: !strcmp(csSec, AIT_GET_STR(&c->cfg_sec)) &&
88: !strcmp(csAttr, AIT_GET_STR(&c->cfg_attr)))
89: return c; /* FOUND! */
90: }
91: return NULL; /* not found */
92: }
1.10 misho 93: do {
94: if (!strcmp(AIT_GET_STR(&c->cfg_attr), csAttr))
95: return c; /* FOUND! */
1.15 misho 96: } while ((c = RB_NEXT(tagRC, cfg, c)) && c && !cfg_tree_cmp(c, &fav));
1.19 misho 97: /* if cannot find right attribute */
98: TAILQ_FOREACH_SAFE(c, cfg, cfg_next, n) {
99: if ((!csSec && AIT_ISEMPTY(&c->cfg_sec)) ||
100: (csSec && !AIT_ISEMPTY(&c->cfg_sec) &&
101: !strcmp(csSec, AIT_GET_STR(&c->cfg_sec))))
102: if (!AIT_ISEMPTY(&c->cfg_attr) && csAttr &&
103: !strcmp(csAttr, AIT_GET_STR(&c->cfg_attr)))
104: return c; /* FOUND! */
105: }
1.10 misho 106: return NULL; /* not found */
107: }
1.1 misho 108: }
109:
1.7 misho 110: /* --------------------------------------------------------------- */
1.18 misho 111:
112: /*
113: * cfg_dumpCfg() - dump config data
114: *
115: * @cfg = Config root
116: * return: none
117: */
118: void
119: cfg_dumpCfg(cfg_root_t * __restrict cfg)
120: {
121: struct tagCfg *r, *c, *ctmp, *q, *qtmp;
1.20 misho 122: int syn = 0;
1.18 misho 123:
124: r = RB_ROOT(cfg);
125: printf("ROOT:: KEY=%.8x [%s] %s=%s\n", ((AIT_KEY(&r->cfg_sec) << 15) | AIT_KEY(&r->cfg_attr)),
126: AIT_ADDR(&r->cfg_sec), AIT_ADDR(&r->cfg_attr), AIT_ADDR(&r->cfg_val));
127:
128: RB_FOREACH_SAFE(c, tagRC, cfg, ctmp) {
129: syn ^= syn;
130: TAILQ_FOREACH_SAFE(q, cfg, cfg_next, qtmp) {
131: if (c == q) {
132: syn = 42;
133: break;
134: }
135: }
136:
137: printf("%s KEY=%.8x [%s] %s=%s sync=%d\n", c == r ? "*" : "",
138: ((AIT_KEY(&c->cfg_sec) << 15) | AIT_KEY(&c->cfg_attr)),
139: AIT_ADDR(&c->cfg_sec), AIT_ADDR(&c->cfg_attr), AIT_ADDR(&c->cfg_val), syn);
140: }
141: }
1.1 misho 142:
143: /*
1.15 misho 144: * cfg_getSection() - Get entire section attributes into array
145: *
146: * @cfg = Config root
147: * @csSec = Config section //[{csSec}]
148: * return: NULL not found or !=NULL allocated array, must free with array_Destroy() after use!
149: */
150: array_t *
151: cfg_getSection(cfg_root_t * __restrict cfg, const char *csSec)
152: {
153: array_t *arr = NULL;
154: struct tagCfg *av, fav;
155:
156: if (!cfg) {
157: cfg_SetErr(EINVAL, "Invalid argument(s)");
158: return NULL;
159: } else
160: memset(&fav, 0, sizeof fav);
161: if (csSec && !*csSec)
162: csSec = NULL;
163:
164: if (csSec && *csSec)
165: AIT_KEY(&fav.cfg_sec) = crcFletcher16((u_short*) csSec,
166: E_ALIGN(strlen(csSec), 2) / 2);
167:
1.17 misho 168: arr = array_Init(0);
1.15 misho 169: if (!arr) {
170: cfg_SetErr(elwix_GetErrno(), "%s", elwix_GetError());
171: return NULL;
1.17 misho 172: }
1.15 misho 173:
1.17 misho 174: TAILQ_FOREACH(av, cfg, cfg_next)
175: if (AIT_KEY(&av->cfg_sec) == AIT_KEY(&fav.cfg_sec)) {
176: if (!csSec) {
177: if (AIT_ISEMPTY(&av->cfg_sec))
178: array_Push(arr, av, 0);
179: } else {
180: if (!AIT_ISEMPTY(&av->cfg_sec) &&
181: !strcmp(AIT_GET_STR(&av->cfg_sec), csSec))
182: array_Push(arr, av, 0);
183: }
1.15 misho 184: }
185:
1.17 misho 186: if (!array_Size(arr))
187: array_Destroy(&arr);
1.15 misho 188:
189: return arr;
190: }
191:
192: /*
1.21 ! misho 193: * cfg_delSection() - Delete entire section
! 194: *
! 195: * @cfg = Config root
! 196: * @csSec = Config section //[{csSec}]
! 197: * return: -1 error, 0 nothing deleted or >0 deleted attributes
! 198: */
! 199: int
! 200: cfg_delSection(cfg_root_t * __restrict cfg, const char *csSec)
! 201: {
! 202: int ret = 0;
! 203: array_t *arr = NULL;
! 204: struct tagCfg *av;
! 205: register int i;
! 206:
! 207: if (!cfg) {
! 208: cfg_SetErr(EINVAL, "Invalid argument(s)");
! 209: return -1;
! 210: }
! 211: if (csSec && !*csSec)
! 212: csSec = NULL;
! 213:
! 214: arr = cfg_getSection(cfg, csSec);
! 215: if (!arr)
! 216: return ret;
! 217: for (i = 0; i < array_Size(arr); i++)
! 218: if ((av = array(arr, i, struct tagCfg*)) && AIT_ADDR(&av->cfg_attr))
! 219: if (cfg_unsetAttribute(cfg, csSec, AIT_GET_STR(&av->cfg_attr)) > 0)
! 220: ret++;
! 221: array_Destroy(&arr);
! 222: return ret;
! 223: }
! 224:
! 225: /*
1.7 misho 226: * cfg_findAttribute() - Find attribute position in config file
227: *
228: * @cfg = Config root
1.1 misho 229: * @csSec = Config section //[{csSec}]
1.19 misho 230: * @csAttr = Config attribute //{csAttr} = ...
1.7 misho 231: * return: 0 not found item, -1 error or >0 position in list
232: */
1.12 misho 233: int
1.7 misho 234: cfg_findAttribute(cfg_root_t * __restrict cfg, const char *csSec, const char *csAttr)
1.1 misho 235: {
1.19 misho 236: struct tagCfg *av, *n;
1.1 misho 237: register int cx = 0;
238:
1.15 misho 239: if (!cfg) {
1.7 misho 240: cfg_SetErr(EINVAL, "Invalid argument(s)");
1.1 misho 241: return -1;
1.19 misho 242: }
1.1 misho 243:
1.19 misho 244: TAILQ_FOREACH_SAFE(av, cfg, cfg_next, n) {
245: ++cx;
1.7 misho 246:
1.19 misho 247: if ((!csSec && AIT_ISEMPTY(&av->cfg_sec)) ||
248: (csSec && !AIT_ISEMPTY(&av->cfg_sec) &&
249: !strcmp(csSec, AIT_GET_STR(&av->cfg_sec))))
250: if (!AIT_ISEMPTY(&av->cfg_attr) && csAttr &&
251: !strcmp(csAttr, AIT_GET_STR(&av->cfg_attr)))
252: return cx;
1.1 misho 253: }
254:
255: return 0;
256: }
257:
258: /*
1.7 misho 259: * cfg_unsetAttribute() - Unset item from config and free resources
260: *
261: * @cfg = Config root
1.1 misho 262: * @csSec = Config section //[{csSec}], if NULL unset in *default* section
1.19 misho 263: * @csAttr = Config attribute //{csAttr} = ...
1.7 misho 264: * return: 0 item not found, -1 error or 1 removed item
265: */
266: int
267: cfg_unsetAttribute(cfg_root_t * __restrict cfg, const char *csSec, const char *csAttr)
1.1 misho 268: {
1.7 misho 269: struct tagCfg *av;
1.1 misho 270:
1.15 misho 271: if (!cfg)
1.1 misho 272: return -1;
273:
1.7 misho 274: av = _selectAttribute(cfg, csSec, csAttr);
1.1 misho 275: if (!av)
276: return 0;
277:
1.7 misho 278: CFG_RC_LOCK(cfg);
279: RB_REMOVE(tagRC, cfg, av);
1.14 misho 280: TAILQ_REMOVE(cfg, av, cfg_next);
1.7 misho 281: CFG_RC_UNLOCK(cfg);
282:
283: AIT_FREE_VAL(&av->cfg_val);
284: AIT_FREE_VAL(&av->cfg_attr);
285: AIT_FREE_VAL(&av->cfg_sec);
1.12 misho 286: e_free(av);
1.7 misho 287: return 1;
1.1 misho 288: }
289:
290: /*
1.7 misho 291: * cfg_setAttribute() - Set item in config or adding new item if not exists
292: *
293: * @cfg = Config root
1.1 misho 294: * @csSec = Config section //[{csSec}], if NULL set in *default* section
1.7 misho 295: * @csAttr = Config attribute //{csAttr} = ...
1.1 misho 296: * @csVal = Config value //... = {csVal} to setup
1.7 misho 297: * return: 0 nothing changed, -1 error, 1 found and updated item or 2 added new item
298: */
299: int
300: cfg_setAttribute(cfg_root_t * __restrict cfg, const char *csSec, const char *csAttr, const char *csVal)
1.1 misho 301: {
1.7 misho 302: struct tagCfg *av, *section;
1.1 misho 303:
304: if (!cfg || !csAttr)
305: return -1;
306:
1.7 misho 307: av = _selectAttribute(cfg, csSec, csAttr);
1.1 misho 308: if (!av) {
1.7 misho 309: /* adding new element */
310: section = _selectAttribute(cfg, csSec, NULL);
1.1 misho 311:
1.12 misho 312: av = e_malloc(sizeof(struct tagCfg));
1.1 misho 313: if (!av) {
314: LOGERR;
315: return -1;
316: } else {
1.7 misho 317: memset(av, 0, sizeof(struct tagCfg));
1.1 misho 318:
1.7 misho 319: CFG_RC_LOCK(cfg);
320: if (!section)
1.14 misho 321: TAILQ_INSERT_TAIL(cfg, av, cfg_next);
1.7 misho 322: else
1.14 misho 323: TAILQ_INSERT_BEFORE(section, av, cfg_next);
1.7 misho 324: CFG_RC_UNLOCK(cfg);
1.1 misho 325: }
1.7 misho 326:
1.1 misho 327: if (csSec && *csSec) {
1.7 misho 328: AIT_SET_STR(&av->cfg_sec, csSec);
329: AIT_KEY(&av->cfg_sec) = crcFletcher16(AIT_GET_LIKE(&av->cfg_sec, u_short*),
1.12 misho 330: E_ALIGN(AIT_LEN(&av->cfg_sec) - 1, 2) / 2);
1.1 misho 331: }
1.7 misho 332: AIT_SET_STR(&av->cfg_val, csVal ? csVal : "");
333: AIT_SET_STR(&av->cfg_attr, csAttr);
334: AIT_KEY(&av->cfg_attr) = crcFletcher16(AIT_GET_LIKE(&av->cfg_attr, u_short*),
1.12 misho 335: E_ALIGN(AIT_LEN(&av->cfg_attr) - 1, 2) / 2);
1.7 misho 336:
337: CFG_RC_LOCK(cfg);
338: RB_INSERT(tagRC, cfg, av);
339: CFG_RC_UNLOCK(cfg);
1.1 misho 340: return 2;
341: }
342:
1.10 misho 343: if (csVal && AIT_ADDR(&av->cfg_val) &&
344: strcmp((char*) csVal, (char*) AIT_GET_STR(&av->cfg_val))) {
1.7 misho 345: /* Update element */
346: AIT_FREE_VAL(&av->cfg_val);
347: AIT_SET_STR(&av->cfg_val, csVal);
1.1 misho 348: return 1;
349: }
350:
1.7 misho 351: /* Nothing happens ... found & values is equal! */
1.1 misho 352: return 0;
353: }
354:
355: /*
1.7 misho 356: * cfg_getAttribute() - Get item from config and return value from it
357: *
358: * @cfg = Config root
1.1 misho 359: * @csSec = Config section //[{csSec}], if NULL unset in *default* section
1.19 misho 360: * @csAttr = Config attribute //{csAttr} = ...
1.7 misho 361: * return: NULL item not found or null parameters, !=NULL value const string
362: */
1.12 misho 363: const char *
1.7 misho 364: cfg_getAttribute(cfg_root_t * __restrict cfg, const char *csSec, const char *csAttr)
1.1 misho 365: {
1.7 misho 366: struct tagCfg *av;
1.1 misho 367:
1.15 misho 368: if (!cfg)
1.1 misho 369: return NULL;
370:
1.7 misho 371: av = _selectAttribute(cfg, csSec, csAttr);
1.1 misho 372: if (!av)
373: return NULL;
374:
1.7 misho 375: return AIT_GET_STR(&av->cfg_val);
1.4 misho 376: }
377:
1.1 misho 378: /*
1.16 misho 379: * cfg_getAttributeLong() - Get item as long from config and return value from it
380: *
381: * @cfg = Config root
382: * @csSec = Config section //[{csSec}], if NULL unset in *default* section
1.19 misho 383: * @csAttr = Config attribute //{csAttr} = ...
1.16 misho 384: * return: value
385: */
386: long
387: cfg_getAttributeLong(cfg_root_t * __restrict cfg, const char *csSec, const char *csAttr)
388: {
389: const char *str = NULL;
390:
391: str = cfg_getAttribute(cfg, csSec, csAttr);
392: return strtol(str ? str : "", NULL, 0);
393: }
394:
395: /*
396: * cfg_getAttributeLLong() - Get item as long long from config and return value from it
397: *
398: * @cfg = Config root
399: * @csSec = Config section //[{csSec}], if NULL unset in *default* section
1.19 misho 400: * @csAttr = Config attribute //{csAttr} = ...
1.16 misho 401: * return: value
402: */
403: long long
404: cfg_getAttributeLLong(cfg_root_t * __restrict cfg, const char *csSec, const char *csAttr)
405: {
406: const char *str = NULL;
407:
408: str = cfg_getAttribute(cfg, csSec, csAttr);
409: return strtoll(str ? str : "", NULL, 0);
410: }
411:
412: /*
413: * cfg_getAttributeDouble() - Get item as double from config and return value from it
414: *
415: * @cfg = Config root
416: * @csSec = Config section //[{csSec}], if NULL unset in *default* section
1.19 misho 417: * @csAttr = Config attribute //{csAttr} = ...
1.16 misho 418: * return: value
419: */
420: double
421: cfg_getAttributeDouble(cfg_root_t * __restrict cfg, const char *csSec, const char *csAttr)
422: {
423: const char *str = NULL;
424:
425: str = cfg_getAttribute(cfg, csSec, csAttr);
426: return strtod(str ? str : "", NULL);
427: }
428:
429: /*
430: * cfg_getAttributeLDouble() - Get item as long double from config and return value from it
431: *
432: * @cfg = Config root
433: * @csSec = Config section //[{csSec}], if NULL unset in *default* section
1.19 misho 434: * @csAttr = Config attribute //{csAttr} = ...
1.16 misho 435: * return: value
436: */
437: long double
438: cfg_getAttributeLDouble(cfg_root_t * __restrict cfg, const char *csSec, const char *csAttr)
439: {
440: const char *str = NULL;
441:
442: str = cfg_getAttribute(cfg, csSec, csAttr);
443: return strtold(str ? str : "", NULL);
444: }
445:
446: /*
1.7 misho 447: * cfg_loadAttribute() - Get guarded attribute, if not found item return *default value*
448: *
449: * @cfg = Config root
1.1 misho 450: * @csSec = Config section //[{csSec}], if NULL unset in *default* section
1.19 misho 451: * @csAttr = Config attribute //{csAttr} = ...
1.7 misho 452: * @val = Return buffer for item Value //... = {val}
453: * @csDefValue = *Default Value* for return in //{val}, if not found item in config
454: * return: 0 item not found, -1 error or >0 number of copied bytes in //{val}
455: */
456: int
457: cfg_loadAttribute(cfg_root_t * __restrict cfg, const char *csSec, const char *csAttr,
458: ait_val_t * __restrict val, const char *csDefValue)
1.1 misho 459: {
1.7 misho 460: struct tagCfg *av;
1.1 misho 461: int ret = 0;
462:
1.15 misho 463: if (!cfg || !val) {
1.7 misho 464: cfg_SetErr(EINVAL, "Invalid argument(s)");
1.1 misho 465: return -1;
1.7 misho 466: }
1.1 misho 467:
1.9 misho 468: AIT_INIT_VAL(val);
1.7 misho 469: av = _selectAttribute(cfg, csSec, csAttr);
1.1 misho 470: if (!av) {
1.7 misho 471: /* not found item */
1.1 misho 472: if (csDefValue) {
1.7 misho 473: AIT_SET_STR(val, csDefValue);
474: ret = AIT_LEN(val);
1.8 misho 475: } else
476: AIT_INIT_VAL(val);
1.1 misho 477: return ret;
478: }
479:
1.10 misho 480: if (AIT_ISEMPTY(&av->cfg_val) || !AIT_ADDR(&av->cfg_val) ||
481: !*AIT_GET_LIKE(&av->cfg_val, char*)) {
1.7 misho 482: /* empty value */
1.1 misho 483: if (csDefValue) {
1.7 misho 484: AIT_SET_STR(val, csDefValue);
485: ret = AIT_LEN(val);
1.8 misho 486: } else
487: AIT_INIT_VAL(val);
1.1 misho 488: } else {
1.7 misho 489: /* copy value */
490: AIT_SET_STR(val, AIT_GET_STR(&av->cfg_val));
491: ret = AIT_LEN(val);
1.1 misho 492: }
493:
494: return ret;
495: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>