+ memcpy (mem + c_size, "\n", 1);
+ c_size ++;
+ sec = sec->next;
+ }
+ GNUNET_assert (c_size == m_size);
+ *size = c_size;
+ return mem;
+}
+
+
+/**
+ * Write configuration file.
+ *
+ * @param cfg configuration to write
+ * @param filename where to write the configuration
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
+ */
+int
+GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *cfg,
+ const char *filename)
+{
+ char *fn;
+ char *cfg_buf;
+ size_t size;
+
+ fn = GNUNET_STRINGS_filename_expand (filename);
+ if (fn == NULL)
+ return GNUNET_SYSERR;
+ if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (fn))
+ {
+ GNUNET_free (fn);
+ return GNUNET_SYSERR;
+ }
+ cfg_buf = GNUNET_CONFIGURATION_serialize (cfg, &size);
+ if (size != GNUNET_DISK_fn_write (fn, cfg_buf, size,
+ GNUNET_DISK_PERM_USER_READ
+ | GNUNET_DISK_PERM_USER_WRITE
+ | GNUNET_DISK_PERM_GROUP_READ
+ | GNUNET_DISK_PERM_GROUP_WRITE))
+ {
+ GNUNET_free (fn);
+ GNUNET_free (cfg_buf);
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Writing configration to file: %s failed\n", filename);
+ cfg->dirty = GNUNET_SYSERR; /* last write failed */
+ return GNUNET_SYSERR;
+ }
+ GNUNET_free (fn);
+ GNUNET_free (cfg_buf);
+ cfg->dirty = GNUNET_NO; /* last write succeeded */
+ return GNUNET_OK;
+}
+
+
+/**
+ * Iterate over all options in the configuration.
+ *
+ * @param cfg configuration to inspect
+ * @param iter function to call on each option
+ * @param iter_cls closure for @a iter
+ */
+void
+GNUNET_CONFIGURATION_iterate (const struct GNUNET_CONFIGURATION_Handle *cfg,
+ GNUNET_CONFIGURATION_Iterator iter,
+ void *iter_cls)
+{
+ struct ConfigSection *spos;
+ struct ConfigEntry *epos;
+
+ for (spos = cfg->sections; NULL != spos; spos = spos->next)
+ for (epos = spos->entries; NULL != epos; epos = epos->next)
+ if (NULL != epos->val)
+ iter (iter_cls, spos->name, epos->key, epos->val);
+}
+
+
+/**
+ * Iterate over values of a section in the configuration.
+ *
+ * @param cfg configuration to inspect
+ * @param section the section
+ * @param iter function to call on each option
+ * @param iter_cls closure for @a iter
+ */
+void
+GNUNET_CONFIGURATION_iterate_section_values (const struct
+ GNUNET_CONFIGURATION_Handle *cfg,
+ const char *section,
+ GNUNET_CONFIGURATION_Iterator iter,
+ void *iter_cls)
+{
+ struct ConfigSection *spos;
+ struct ConfigEntry *epos;
+
+ spos = cfg->sections;
+ while ((spos != NULL) && (0 != strcasecmp (spos->name, section)))
+ spos = spos->next;
+ if (NULL == spos)
+ return;
+ for (epos = spos->entries; NULL != epos; epos = epos->next)
+ if (NULL != epos->val)
+ iter (iter_cls, spos->name, epos->key, epos->val);
+}
+
+
+/**
+ * Iterate over all sections in the configuration.
+ *
+ * @param cfg configuration to inspect
+ * @param iter function to call on each section
+ * @param iter_cls closure for @a iter
+ */
+void
+GNUNET_CONFIGURATION_iterate_sections (const struct GNUNET_CONFIGURATION_Handle *cfg,
+ GNUNET_CONFIGURATION_Section_Iterator iter,
+ void *iter_cls)
+{
+ struct ConfigSection *spos;
+ struct ConfigSection *next;
+
+ next = cfg->sections;
+ while (next != NULL)
+ {
+ spos = next;
+ next = spos->next;
+ iter (iter_cls, spos->name);
+ }
+}
+
+
+/**
+ * Remove the given section and all options in it.
+ *
+ * @param cfg configuration to inspect
+ * @param section name of the section to remove
+ */
+void
+GNUNET_CONFIGURATION_remove_section (struct GNUNET_CONFIGURATION_Handle *cfg,
+ const char *section)
+{
+ struct ConfigSection *spos;
+ struct ConfigSection *prev;
+ struct ConfigEntry *ent;
+
+ prev = NULL;
+ spos = cfg->sections;
+ while (NULL != spos)
+ {
+ if (0 == strcasecmp (section, spos->name))