2 * UCW Library -- Configuration files: sections
4 * (c) 2001--2006 Robert Spalek <robert@ucw.cz>
5 * (c) 2003--2006 Martin Mares <mj@ucw.cz>
7 * This software may be freely distributed and used according to the terms
8 * of the GNU Lesser General Public License.
13 #include "lib/conf-internal.h"
14 #include "lib/clists.h"
15 #include "lib/binsearch.h"
21 struct dirty_section {
22 struct cf_section *sec;
25 #define GBUF_TYPE struct dirty_section
26 #define GBUF_PREFIX(x) dirtsec_##x
28 static dirtsec_t dirty;
32 cf_add_dirty(struct cf_section *sec, void *ptr)
34 dirtsec_grow(&dirty, dirties+1);
35 struct dirty_section *dest = dirty.ptr + dirties;
36 if (dirties && dest[-1].sec == sec && dest[-1].ptr == ptr)
43 #define ASORT_PREFIX(x) dirtsec_##x
44 #define ASORT_KEY_TYPE struct dirty_section
45 #define ASORT_ELT(i) dirty.ptr[i]
46 #define ASORT_LT(x,y) x.sec < y.sec || x.sec == y.sec && x.ptr < y.ptr
47 #include "lib/arraysort.h"
54 dirtsec_sort(dirties);
55 // and compress the list
56 struct dirty_section *read = dirty.ptr + 1, *write = dirty.ptr + 1, *limit = dirty.ptr + dirties;
57 while (read < limit) {
58 if (read->sec != read[-1].sec || read->ptr != read[-1].ptr) {
65 dirties = write - dirty.ptr;
70 struct cf_section cf_sections; // root section
73 cf_find_subitem(struct cf_section *sec, byte *name)
75 struct cf_item *ci = sec->cfg;
77 if (!strcasecmp(ci->name, name))
83 inspect_section(struct cf_section *sec)
87 for (ci=sec->cfg; ci->cls; ci++)
88 if (ci->cls == CC_SECTION) {
89 inspect_section(ci->u.sec);
90 sec->flags |= ci->u.sec->flags & (SEC_FLAG_DYNAMIC | SEC_FLAG_CANT_COPY);
91 } else if (ci->cls == CC_LIST) {
92 inspect_section(ci->u.sec);
93 sec->flags |= SEC_FLAG_DYNAMIC | SEC_FLAG_CANT_COPY;
94 } else if (ci->cls == CC_DYNAMIC || ci->cls == CC_BITMAP)
95 sec->flags |= SEC_FLAG_DYNAMIC;
96 else if (ci->cls == CC_PARSER) {
97 sec->flags |= SEC_FLAG_CANT_COPY;
99 sec->flags |= SEC_FLAG_DYNAMIC;
102 sec->flags &= ~SEC_FLAG_CANT_COPY;
103 sec->flags |= ci - sec->cfg; // record the number of entries
107 cf_declare_section(byte *name, struct cf_section *sec, uns allow_unknown)
109 if (!cf_sections.cfg)
111 cf_sections.size = 50;
112 cf_sections.cfg = xmalloc_zero(cf_sections.size * sizeof(struct cf_item));
114 struct cf_item *ci = cf_find_subitem(&cf_sections, name);
116 die("Cannot register section %s twice", name);
117 ci->cls = CC_SECTION;
122 inspect_section(sec);
124 sec->flags |= SEC_FLAG_UNKNOWN;
126 if (ci - cf_sections.cfg >= (int) cf_sections.size)
128 cf_sections.cfg = xrealloc(cf_sections.cfg, 2*cf_sections.size * sizeof(struct cf_item));
129 bzero(cf_sections.cfg + cf_sections.size, cf_sections.size * sizeof(struct cf_item));
130 cf_sections.size *= 2;
135 cf_init_section(byte *name, struct cf_section *sec, void *ptr, uns do_bzero)
139 bzero(ptr, sec->size);
141 for (struct cf_item *ci=sec->cfg; ci->cls; ci++)
142 if (ci->cls == CC_SECTION)
143 cf_init_section(ci->name, ci->u.sec, ptr + (uintptr_t) ci->ptr, 0);
144 else if (ci->cls == CC_LIST)
145 clist_init(ptr + (uintptr_t) ci->ptr);
146 else if (ci->cls == CC_DYNAMIC) {
147 void **dyn = ptr + (uintptr_t) ci->ptr;
148 if (!*dyn) { // replace NULL by an empty array
154 byte *msg = sec->init(ptr);
156 die("Cannot initialize section %s: %s", name, msg);
161 commit_section(struct cf_section *sec, void *ptr, uns commit_all)
164 for (struct cf_item *ci=sec->cfg; ci->cls; ci++)
165 if (ci->cls == CC_SECTION) {
166 if ((err = commit_section(ci->u.sec, ptr + (uintptr_t) ci->ptr, commit_all))) {
167 log(L_ERROR, "Cannot commit section %s: %s", ci->name, err);
168 return "commit of a subsection failed";
170 } else if (ci->cls == CC_LIST) {
172 CLIST_FOR_EACH(cnode *, n, * (clist*) (ptr + (uintptr_t) ci->ptr))
173 if (idx++, err = commit_section(ci->u.sec, n, commit_all)) {
174 log(L_ERROR, "Cannot commit node #%d of list %s: %s", idx, ci->name, err);
175 return "commit of a list failed";
179 /* We have to process the whole tree of sections even if just a few changes
180 * have been made, because there are dependencies between commit-hooks and
181 * hence we need to call them in a fixed order. */
182 #define ARY_LT_X(ary,i,x) ary[i].sec < x.sec || ary[i].sec == x.sec && ary[i].ptr < x.ptr
183 struct dirty_section comp = { sec, ptr };
184 uns pos = BIN_SEARCH_FIRST_GE_CMP(dirty.ptr, dirties, comp, ARY_LT_X);
187 || (pos < dirties && dirty.ptr[pos].sec == sec && dirty.ptr[pos].ptr == ptr))
188 return sec->commit(ptr);
194 cf_commit_all(enum cf_commit_mode cm)
197 if (cm == CF_NO_COMMIT)
199 if (commit_section(&cf_sections, NULL, cm == CF_COMMIT_ALL))