2 * UCW Library -- Configuration files: sections
4 * (c) 2001--2006 Robert Spalek <robert@ucw.cz>
5 * (c) 2003--2012 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 <ucw/conf-internal.h>
14 #include <ucw/clists.h>
15 #include <ucw/binsearch.h>
23 struct dirty_section {
24 struct cf_section *sec;
27 #define GBUF_TYPE struct dirty_section
28 #define GBUF_PREFIX(x) dirtsec_##x
30 static dirtsec_t dirty;
34 cf_add_dirty(struct cf_section *sec, void *ptr)
36 dirtsec_grow(&dirty, dirties+1);
37 struct dirty_section *dest = dirty.ptr + dirties;
38 if (dirties && dest[-1].sec == sec && dest[-1].ptr == ptr)
45 #define ASORT_PREFIX(x) dirtsec_##x
46 #define ASORT_KEY_TYPE struct dirty_section
47 #define ASORT_ELT(i) dirty.ptr[i]
48 #define ASORT_LT(x,y) x.sec < y.sec || x.sec == y.sec && x.ptr < y.ptr
49 #include <ucw/sorter/array-simple.h>
56 dirtsec_sort(dirties);
57 // and compress the list
58 struct dirty_section *read = dirty.ptr + 1, *write = dirty.ptr + 1, *limit = dirty.ptr + dirties;
59 while (read < limit) {
60 if (read->sec != read[-1].sec || read->ptr != read[-1].ptr) {
67 dirties = write - dirty.ptr;
73 cf_find_subitem(struct cf_section *sec, const char *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(const char *name, struct cf_section *sec, uns allow_unknown)
109 struct cf_context *cc = cf_get_context();
110 if (!cc->sections.cfg)
112 cc->sections.size = 50;
113 cc->sections.cfg = xmalloc_zero(cc->sections.size * sizeof(struct cf_item));
115 struct cf_item *ci = cf_find_subitem(&cc->sections, name);
117 die("Cannot register section %s twice", name);
118 ci->cls = CC_SECTION;
123 inspect_section(sec);
125 sec->flags |= SEC_FLAG_UNKNOWN;
127 if (ci - cc->sections.cfg >= (int) cc->sections.size)
129 cc->sections.cfg = xrealloc(cc->sections.cfg, 2*cc->sections.size * sizeof(struct cf_item));
130 bzero(cc->sections.cfg + cc->sections.size, cc->sections.size * sizeof(struct cf_item));
131 cc->sections.size *= 2;
136 cf_init_section(const char *name, struct cf_section *sec, void *ptr, uns do_bzero)
140 bzero(ptr, sec->size);
142 for (struct cf_item *ci=sec->cfg; ci->cls; ci++)
143 if (ci->cls == CC_SECTION)
144 cf_init_section(ci->name, ci->u.sec, ptr + (uintptr_t) ci->ptr, 0);
145 else if (ci->cls == CC_LIST)
146 clist_init(ptr + (uintptr_t) ci->ptr);
147 else if (ci->cls == CC_DYNAMIC) {
148 void **dyn = ptr + (uintptr_t) ci->ptr;
149 if (!*dyn) { // replace NULL by an empty array
155 char *msg = sec->init(ptr);
157 die("Cannot initialize section %s: %s", name, msg);
162 commit_section(struct cf_section *sec, void *ptr, uns commit_all)
165 for (struct cf_item *ci=sec->cfg; ci->cls; ci++)
166 if (ci->cls == CC_SECTION) {
167 if ((err = commit_section(ci->u.sec, ptr + (uintptr_t) ci->ptr, commit_all))) {
168 msg(L_ERROR, "Cannot commit section %s: %s", ci->name, err);
169 return "commit of a subsection failed";
171 } else if (ci->cls == CC_LIST) {
173 CLIST_FOR_EACH(cnode *, n, * (clist*) (ptr + (uintptr_t) ci->ptr))
174 if (idx++, err = commit_section(ci->u.sec, n, commit_all)) {
175 msg(L_ERROR, "Cannot commit node #%d of list %s: %s", idx, ci->name, err);
176 return "commit of a list failed";
180 /* We have to process the whole tree of sections even if just a few changes
181 * have been made, because there are dependencies between commit-hooks and
182 * hence we need to call them in a fixed order. */
183 #define ARY_LT_X(ary,i,x) ary[i].sec < x.sec || ary[i].sec == x.sec && ary[i].ptr < x.ptr
184 struct dirty_section comp = { sec, ptr };
185 uns pos = BIN_SEARCH_FIRST_GE_CMP(dirty.ptr, dirties, comp, ARY_LT_X);
188 || (pos < dirties && dirty.ptr[pos].sec == sec && dirty.ptr[pos].ptr == ptr))
189 return sec->commit(ptr);
195 cf_commit_all(enum cf_commit_mode cm)
197 struct cf_context *cc = cf_get_context();
199 if (cm == CF_NO_COMMIT)
201 if (commit_section(&cc->sections, NULL, cm == CF_COMMIT_ALL))