#define SEC_FLAG_DYNAMIC 0x80000000 // contains a dynamic attribute
#define SEC_FLAG_UNKNOWN 0x40000000 // ignore unknown entriies
-#define SEC_FLAG_CANT_DUPLICATE 0x20000000 // contains lists or parsers
+#define SEC_FLAG_CANT_COPY 0x20000000 // contains lists or parsers
#define SEC_FLAG_NUMBER 0x0fffffff // number of entries
static struct cf_section sections; // root section
for (ci=sec->cfg; ci->cls; ci++)
if (ci->cls == CC_SECTION) {
inspect_section(ci->u.sec);
- sec->flags |= ci->u.sec->flags & (SEC_FLAG_DYNAMIC | SEC_FLAG_CANT_DUPLICATE);
+ sec->flags |= ci->u.sec->flags & (SEC_FLAG_DYNAMIC | SEC_FLAG_CANT_COPY);
} else if (ci->cls == CC_LIST) {
inspect_section(ci->u.sec);
- sec->flags |= SEC_FLAG_DYNAMIC | SEC_FLAG_CANT_DUPLICATE;
+ sec->flags |= SEC_FLAG_DYNAMIC | SEC_FLAG_CANT_COPY;
} else if (ci->cls == CC_DYNAMIC)
sec->flags |= SEC_FLAG_DYNAMIC;
else if (ci->cls == CC_PARSER) {
- sec->flags |= SEC_FLAG_CANT_DUPLICATE;
+ sec->flags |= SEC_FLAG_CANT_COPY;
if (ci->number < 0)
sec->flags |= SEC_FLAG_DYNAMIC;
}
+ if (sec->copy)
+ sec->flags &= ~SEC_FLAG_CANT_COPY;
sec->flags |= ci - sec->cfg; // record the number of entries
}
break;
case OP_AFTER: // implementation dependend (prepend_head = after(list)), and where==list, see clists.h:74
case OP_PREPEND:
- case OP_DUPLICATE:
+ case OP_COPY:
cf_journal_block(&where->next->prev, sizeof(void*));
cf_journal_block(&where->next, sizeof(void*));
clist_insert_after(new_node, where);
st->base_ptr = st->list;
else if (pure_op == OP_AFTER || pure_op == OP_BEFORE)
cf_init_section(st->item->name, st->sec, st->base_ptr, 1);
- else if (pure_op == OP_DUPLICATE) {
- if (st->sec->flags & SEC_FLAG_CANT_DUPLICATE)
- return cf_printf("Item %s cannot be duplicated", st->item->name);
+ else if (pure_op == OP_COPY) {
+ if (st->sec->flags & SEC_FLAG_CANT_COPY)
+ return cf_printf("Item %s cannot be copied", st->item->name);
memcpy(st->base_ptr, st->list, st->sec->size); // strings and dynamic arrays are shared
+ if (st->sec->copy)
+ TRY( st->sec->copy(st->base_ptr, st->list) );
} else
ASSERT(0);
if (op & OP_OPEN) { // stay at the same recursion level
*c++ = 0;
switch (Clocase(*c)) {
case 's': op = OP_SET; break;
- case 'c': op = OP_CLEAR; break;
+ case 'c': op = Clocase(c[1]) == 'l' ? OP_CLEAR: OP_COPY; break;
case 'a': op = Clocase(c[1]) == 'p' ? OP_APPEND : OP_AFTER; break;
case 'p': op = OP_PREPEND; break;
case 'r': op = OP_REMOVE; break;
case 'e': op = OP_EDIT; break;
case 'b': op = OP_BEFORE; break;
- case 'd': op = OP_DUPLICATE; break;
default: op = OP_SET; break;
}
if (strcasecmp(c, op_names[op])) {
* use cf_malloc() but normal xmalloc(). */
typedef void cf_dumper1(struct fastbuf *fb, void *ptr);
/* Dumps the contents of a variable of a user-defined type. */
+typedef byte *cf_copier(void *dest, void *src);
+ /* Similar to init-hook, but it copies attributes from another list node
+ * instead of setting the attributes to default values. You have to provide
+ * it if your node contains parsed values and/or sub-lists. */
struct cf_user_type {
uns size; // of the parsed attribute
uns size; // 0 for a global block, sizeof(struct) for a section
cf_hook *init; // fills in default values (no need to bzero)
cf_hook *commit; // verifies parsed data (optional)
+ cf_copier *copy; // copies values from another instance (optional, no need to copy basic attributes)
struct cf_item *cfg; // CC_END-terminated array of items
uns flags; // for internal use only
};
#define CF_TYPE(s) .size = sizeof(s)
#define CF_INIT(f) .init = (cf_hook*) f
#define CF_COMMIT(f) .commit = (cf_hook*) f
+#define CF_COPY(f) .copy = (cf_copier*) f
#define CF_ITEMS .cfg = ( struct cf_item[] )
#define CF_END { .cls = CC_END }
/* Configuration items */
/* Direct access to configuration items */
#define CF_OPERATIONS T(CLOSE) T(SET) T(CLEAR) T(APPEND) T(PREPEND) \
- T(REMOVE) T(EDIT) T(AFTER) T(BEFORE) T(DUPLICATE)
+ T(REMOVE) T(EDIT) T(AFTER) T(BEFORE) T(COPY)
/* Closing brace finishes previous block.
* Basic attributes (static, dynamic, parsed) can be used with SET.
* Dynamic arrays can be used with SET, APPEND, PREPEND.