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>
22 cf_add_dirty(struct cf_section *sec, void *ptr)
24 struct cf_context *cc = cf_get_context();
25 dirtsec_grow(&cc->dirty, cc->dirties+1);
26 struct dirty_section *dest = cc->dirty.ptr + cc->dirties;
27 if (cc->dirties && dest[-1].sec == sec && dest[-1].ptr == ptr)
34 #define ASORT_PREFIX(x) dirtsec_##x
35 #define ASORT_KEY_TYPE struct dirty_section
36 #define ASORT_LT(x,y) x.sec < y.sec || x.sec == y.sec && x.ptr < y.ptr
37 #include <ucw/sorter/array-simple.h>
40 sort_dirty(struct cf_context *cc)
44 dirtsec_sort(cc->dirty.ptr, cc->dirties);
45 // and compress the list
46 struct dirty_section *read = cc->dirty.ptr + 1, *write = cc->dirty.ptr + 1, *limit = cc->dirty.ptr + cc->dirties;
47 while (read < limit) {
48 if (read->sec != read[-1].sec || read->ptr != read[-1].ptr) {
55 cc->dirties = write - cc->dirty.ptr;
61 cf_find_subitem(struct cf_section *sec, const char *name)
63 struct cf_item *ci = sec->cfg;
65 if (!strcasecmp(ci->name, name))
71 inspect_section(struct cf_section *sec)
75 for (ci=sec->cfg; ci->cls; ci++)
76 if (ci->cls == CC_SECTION) {
77 inspect_section(ci->u.sec);
78 sec->flags |= ci->u.sec->flags & (SEC_FLAG_DYNAMIC | SEC_FLAG_CANT_COPY);
79 } else if (ci->cls == CC_LIST) {
80 inspect_section(ci->u.sec);
81 sec->flags |= SEC_FLAG_DYNAMIC | SEC_FLAG_CANT_COPY;
82 } else if (ci->cls == CC_DYNAMIC || ci->cls == CC_BITMAP)
83 sec->flags |= SEC_FLAG_DYNAMIC;
84 else if (ci->cls == CC_PARSER) {
85 sec->flags |= SEC_FLAG_CANT_COPY;
87 sec->flags |= SEC_FLAG_DYNAMIC;
90 sec->flags &= ~SEC_FLAG_CANT_COPY;
91 sec->flags |= ci - sec->cfg; // record the number of entries
95 cf_declare_rel_section(const char *name, struct cf_section *sec, void *ptr, uns allow_unknown)
97 struct cf_context *cc = cf_obtain_context();
98 if (!cc->sections.cfg)
100 cc->sections.size = 50;
101 cc->sections.cfg = xmalloc_zero(cc->sections.size * sizeof(struct cf_item));
103 struct cf_item *ci = cf_find_subitem(&cc->sections, name);
105 die("Cannot register section %s twice", name);
106 ci->cls = CC_SECTION;
111 inspect_section(sec);
113 sec->flags |= SEC_FLAG_UNKNOWN;
115 if (ci - cc->sections.cfg >= (int) cc->sections.size)
117 cc->sections.cfg = xrealloc(cc->sections.cfg, 2*cc->sections.size * sizeof(struct cf_item));
118 bzero(cc->sections.cfg + cc->sections.size, cc->sections.size * sizeof(struct cf_item));
119 cc->sections.size *= 2;
124 cf_declare_section(const char *name, struct cf_section *sec, uns allow_unknown)
126 cf_declare_rel_section(name, sec, NULL, allow_unknown);
130 cf_init_section(const char *name, struct cf_section *sec, void *ptr, uns do_bzero)
134 bzero(ptr, sec->size);
136 for (struct cf_item *ci=sec->cfg; ci->cls; ci++)
137 if (ci->cls == CC_SECTION)
138 cf_init_section(ci->name, ci->u.sec, ptr + (uintptr_t) ci->ptr, 0);
139 else if (ci->cls == CC_LIST)
140 clist_init(ptr + (uintptr_t) ci->ptr);
141 else if (ci->cls == CC_DYNAMIC) {
142 void **dyn = ptr + (uintptr_t) ci->ptr;
143 if (!*dyn) { // replace NULL by an empty array
149 char *msg = sec->init(ptr);
151 die("Cannot initialize section %s: %s", name, msg);
156 commit_section(struct cf_section *sec, void *ptr, uns commit_all)
158 struct cf_context *cc = cf_get_context();
161 for (struct cf_item *ci=sec->cfg; ci->cls; ci++)
162 if (ci->cls == CC_SECTION) {
163 if ((err = commit_section(ci->u.sec, ptr + (uintptr_t) ci->ptr, commit_all))) {
164 msg(L_ERROR, "Cannot commit section %s: %s", ci->name, err);
165 return "commit of a subsection failed";
167 } else if (ci->cls == CC_LIST) {
169 CLIST_FOR_EACH(cnode *, n, * (clist*) (ptr + (uintptr_t) ci->ptr))
170 if (idx++, err = commit_section(ci->u.sec, n, commit_all)) {
171 msg(L_ERROR, "Cannot commit node #%d of list %s: %s", idx, ci->name, err);
172 return "commit of a list failed";
176 /* We have to process the whole tree of sections even if just a few changes
177 * have been made, because there are dependencies between commit-hooks and
178 * hence we need to call them in a fixed order. */
179 #define ARY_LT_X(ary,i,x) ary[i].sec < x.sec || ary[i].sec == x.sec && ary[i].ptr < x.ptr
180 struct dirty_section comp = { sec, ptr };
181 uns pos = BIN_SEARCH_FIRST_GE_CMP(cc->dirty.ptr, cc->dirties, comp, ARY_LT_X);
184 || (pos < cc->dirties && cc->dirty.ptr[pos].sec == sec && cc->dirty.ptr[pos].ptr == ptr))
185 return sec->commit(ptr);
191 cf_commit_all(enum cf_commit_mode cm)
193 struct cf_context *cc = cf_get_context();
195 if (cm == CF_NO_COMMIT)
197 if (commit_section(&cc->sections, NULL, cm == CF_COMMIT_ALL))