+ return sec;
+}
+
+static bb_t path;
+
+static void
+dump_value(uns array, struct item *item, void *v)
+{
+ byte buf[128], *value = buf;
+ if (!array)
+ printf("CF_%s_%s='", path.ptr, item->cf.name);
+ else
+ printf("CF_%s_%s[%u]='", path.ptr, item->cf.name, ++item->index);
+ switch (item->cf.type)
+ {
+ case CT_INT:
+ sprintf(buf, "%d", *(int *)v);
+ break;
+ case CT_U64:
+ sprintf(buf, "%llu", (long long) *(u64 *)v);
+ break;
+ case CT_DOUBLE:
+ sprintf(buf, "%g", *(double *)v);
+ break;
+ case CT_STRING:
+ if (*(byte **)v)
+ value = *(byte **)v;
+ else
+ *value = 0;
+ break;
+ default:
+ ASSERT(0);
+ }
+ while (*value) {
+ if (*value == '\'')
+ printf("'\\''");
+ else
+ putchar(*value);
+ value++;
+ }
+ printf("'\n");
+}
+
+static void
+dump_item(struct item *item, void *ptr, uns path_len)
+{
+ if (item->flags & FLAG_HIDE)
+ return;
+ byte *val = (byte *)((uintptr_t)ptr + (uintptr_t)item->cf.ptr);
+ if (item->cf.cls == CC_LIST)
+ {
+ uns len = strlen(item->cf.name);
+ bb_grow(&path, path_len + len + 1);
+ path.ptr[path_len] = '_';
+ memcpy(path.ptr + path_len + 1, item->cf.name, len);
+ CLIST_FOR_EACH(cnode *, ptr2, *(clist *)val)
+ CLIST_FOR_EACH(struct item *, item2, ((struct section *)item)->list)
+ dump_item(item2, ptr2, path_len + len + 1);
+ }
+ else
+ {
+ bb_grow(&path, path_len + 1)[path_len] = 0;
+ if (item->cf.cls == CC_STATIC)
+ dump_value(!!ptr, item, val);
+ else
+ {
+ val = *(void **)val;
+ uns len = DARY_LEN(val);
+ uns size = cf_type_size(item->cf.type, NULL);
+ for (uns i = 0; i < len; i++, val += size)
+ dump_value(1, item, val);
+ }
+ }
+}
+
+int main(int argc, char **argv)
+{
+ log_init("config");
+ if (argc < 2)
+ help();
+ pos = argv[argc - 1];
+ argv[argc - 1] = NULL;
+
+ pool = mp_new(0x1000);
+ clist_init(§ions);
+ parse_outer();
+ CLIST_FOR_EACH(struct section *, sec, sections)
+ cf_declare_section(sec->item.cf.name, generate_section(sec), !(sec->item.flags & FLAG_NO_UNKNOWN));
+
+ if (cf_getopt(argc - 1, argv, CF_SHORT_OPTS, CF_NO_LONG_OPTS, NULL) != -1)