#include <stdlib.h>
#include <string.h>
#include <sys/queue.h>
+#include <unistd.h>
+#include "address.h"
#include "config.h"
#include "logging.h"
#include "string.h"
char value[NETWORK_CONFIG_KEY_MAX_LENGTH];
};
+struct nw_config_option {
+ STAILQ_ENTRY(nw_config_option) nodes;
+
+ const char* key;
+ void* value;
+ size_t length;
+
+ // Callbacks
+ nw_config_option_read_callback_t read_callback;
+ nw_config_option_write_callback_t write_callback;
+ void* data;
+};
+
struct nw_config {
int nrefs;
- // The path to the configuration file
- char path[PATH_MAX];
+ STAILQ_HEAD(config_entries, nw_config_entry) entries;
- STAILQ_HEAD(entries, nw_config_entry) entries;
+ // Options
+ STAILQ_HEAD(parser_entries, nw_config_option) options;
};
static void nw_config_entry_free(struct nw_config_entry* entry) {
free(entry);
}
+static void nw_config_option_free(struct nw_config_option* option) {
+ free(option);
+}
+
static struct nw_config_entry* nw_config_entry_create(
nw_config* config, const char* key) {
int r;
}
static void nw_config_free(nw_config* config) {
+ struct nw_config_option* option = NULL;
+
// Flush all entries
nw_config_flush(config);
+ // Free all options
+ while (!STAILQ_EMPTY(&config->options)) {
+ option = STAILQ_FIRST(&config->options);
+ STAILQ_REMOVE_HEAD(&config->options, nodes);
+
+ // Free the options
+ nw_config_option_free(option);
+ }
+
free(config);
}
-int nw_config_create(nw_config** config, const char* path) {
+int nw_config_create(nw_config** config, FILE* f) {
int r;
nw_config* c = calloc(1, sizeof(*c));
// Initialise entries
STAILQ_INIT(&c->entries);
- // Store the path
- if (path) {
- r = nw_string_set(c->path, path);
- if (r)
- goto ERROR;
+ // Initialise options
+ STAILQ_INIT(&c->options);
- // Try to read the configuration from path
- r = nw_config_read(c);
- if (r)
+ // Read configuration
+ if (f) {
+ r = nw_config_read(c, f);
+ if (r < 0)
goto ERROR;
}
return r;
}
+int nw_config_open(nw_config** config, const char* path) {
+ FILE* f = NULL;
+ int r;
+
+ // Open path
+ f = fopen(path, "r");
+ if (!f)
+ return -errno;
+
+ // Create a new configuration
+ r = nw_config_create(config, f);
+
+ERROR:
+ if (f)
+ fclose(f);
+
+ return r;
+}
+
nw_config* nw_config_ref(nw_config* config) {
config->nrefs++;
return NULL;
}
-const char* nw_config_path(nw_config* config) {
- if (*config->path)
- return config->path;
+int nw_config_copy(nw_config* config, nw_config** copy) {
+ struct nw_config_entry* entry = NULL;
+ nw_config* c = NULL;
+ int r;
- return NULL;
+ // Create a new configuration
+ r = nw_config_create(&c, NULL);
+ if (r)
+ return r;
+
+ // Copy everything
+ STAILQ_FOREACH(entry, &config->entries, nodes) {
+ r = nw_config_set(c, entry->key, entry->value);
+ if (r)
+ goto ERROR;
+ }
+
+ *copy = c;
+ return 0;
+
+ERROR:
+ if (c)
+ nw_config_unref(c);
+
+ return r;
}
int nw_config_flush(nw_config* config) {
return 0;
}
-static int nw_config_readf(nw_config* config, FILE* f) {
+int nw_config_read(nw_config* config, FILE* f) {
char* line = NULL;
size_t length = 0;
int r;
return r;
}
-int nw_config_read(nw_config* config) {
- FILE* f = NULL;
- int r;
-
- // We cannot read if path is not set
- if (!*config->path) {
- errno = ENOTSUP;
- return 1;
- }
-
- // Open the file
- f = fopen(config->path, "r");
- if (!f) {
- // Silently ignore if the file does not exist
- if (errno == ENOENT)
- return 0;
-
- ERROR("Could not read configuration file %s: %m\n", config->path);
- r = 1;
- goto ERROR;
- }
-
- // Read from file
- r = nw_config_readf(config, f);
-
-ERROR:
- if (f)
- fclose(f);
-
- return r;
-}
-
-static int nw_config_writef(nw_config* config, FILE* f) {
+int nw_config_write(nw_config* config, FILE* f) {
struct nw_config_entry* entry = NULL;
int r;
return 0;
}
-int nw_config_write(nw_config* config) {
- int r;
-
- // We cannot write if path is not set
- if (!*config->path) {
- errno = ENOTSUP;
- return 1;
- }
-
- FILE* f = fopen(config->path, "w");
- if (!f) {
- ERROR("Failed to open %s for writing: %m\n", config->path);
- r = 1;
- goto ERROR;
- }
-
- // Write configuration
- r = nw_config_writef(config, f);
-
-ERROR:
- if (f)
- fclose(f);
-
- return r;
-}
-
static struct nw_config_entry* nw_config_find(nw_config* config, const char* key) {
struct nw_config_entry* entry = NULL;
int nw_config_set(nw_config* config, const char* key, const char* value) {
struct nw_config_entry* entry = NULL;
+ // Log the change
+ DEBUG("%p: Setting %s = %s\n", config, key, value);
+
// Delete the entry if val is NULL
if (!value)
return nw_config_del(config, key);
int r;
// Format the value as string
- r = nw_string_format(__value, "%d\n", value);
+ r = nw_string_format(__value, "%d", value);
if (r)
return r;
// Check if we match any known true words
for (const char** s = nw_config_true; *s; s++) {
- if (strcmp(value, *s) == 0)
+ if (strcasecmp(value, *s) == 0)
return 1;
}
int nw_config_set_bool(nw_config* config, const char* key, const int value) {
return nw_config_set(config, key, value ? "true" : "false");
}
+
+/*
+ Options
+*/
+
+int nw_config_options_read(nw_config* config) {
+ struct nw_config_option* option = NULL;
+ int r;
+
+ STAILQ_FOREACH(option, &config->options, nodes) {
+ r = option->read_callback(config,
+ option->key, option->value, option->length, option->data);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+int nw_config_options_write(nw_config* config) {
+ struct nw_config_option* option = NULL;
+ int r;
+
+ STAILQ_FOREACH(option, &config->options, nodes) {
+ r = option->write_callback(config,
+ option->key, option->value, option->length, option->data);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+int nw_config_option_add(nw_config* config,
+ const char* key, void* value, const size_t length,
+ nw_config_option_read_callback_t read_callback,
+ nw_config_option_write_callback_t write_callback, void* data) {
+ // Check input
+ if (!key || !value || !read_callback || !write_callback)
+ return -EINVAL;
+
+ // Allocate a new option
+ struct nw_config_option* option = calloc(1, sizeof(*option));
+ if (!option)
+ return -errno;
+
+ // Set key
+ option->key = key;
+
+ // Set value
+ option->value = value;
+ option->length = length;
+
+ // Set callbacks
+ option->read_callback = read_callback;
+ option->write_callback = write_callback;
+ option->data = data;
+
+ // Append the new option
+ STAILQ_INSERT_TAIL(&config->options, option, nodes);
+
+ return 0;
+}
+
+int nw_config_read_int(nw_config* config,
+ const char* key, void* value, const size_t length, void* data) {
+ // Fetch the value
+ *(int*)value = nw_config_get_int(config, key, -1);
+
+ return 0;
+}
+
+int nw_config_write_int(nw_config* config,
+ const char* key, const void* value, const size_t length, void* data) {
+ return 0;
+}
+
+// String
+
+int nw_config_read_string(nw_config* config,
+ const char* key, void* value, const size_t length, void* data) {
+ // Fetch the value
+ const char* p = nw_config_get(config, key);
+ if (p)
+ *(const char**)value = p;
+
+ return 0;
+}
+
+int nw_config_write_string(nw_config* config,
+ const char* key, const void* value, const size_t length, void* data) {
+ return nw_config_set(config, key, *(const char**)value);
+}
+
+// String Buffer
+
+int nw_config_read_string_buffer(nw_config* config,
+ const char* key, void* value, const size_t length, void* data) {
+ char* string = (char*)value;
+
+ // Fetch the value
+ const char* p = nw_config_get(config, key);
+ if (p)
+ return __nw_string_set(string, length, p);
+
+ return 0;
+}
+
+// String Table
+
+int nw_config_read_string_table(nw_config* config,
+ const char* key, void* value, const size_t length, void* data) {
+ const char* s = NULL;
+ int* v = (int*)value;
+
+ const nw_string_table_t* table = (nw_string_table_t*)data;
+
+ // Fetch the string
+ s = nw_config_get(config, key);
+ if (!s)
+ return -errno;
+
+ // Lookup the string in the table
+ *v = nw_string_table_lookup_id(table, s);
+
+ // If the result is negative, nothing was found
+ if (*v < 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+int nw_config_write_string_table(nw_config* config,
+ const char* key, const void* value, const size_t length, void* data) {
+ int* v = (int*)value;
+
+ const nw_string_table_t* table = (nw_string_table_t*)data;
+
+ // Lookup the string
+ const char* s = nw_string_table_lookup_string(table, *v);
+ if (!s)
+ return -errno;
+
+ return nw_config_set(config, key, s);
+}
+
+// Address
+
+int nw_config_read_address(nw_config* config,
+ const char* key, void* value, const size_t length, void* data) {
+ nw_address_t* address = (nw_address_t*)value;
+ int r;
+
+ // Fetch the value
+ const char* p = nw_config_get(config, key);
+ if (!p)
+ return -EINVAL;
+
+ r = nw_address_from_string(address, p);
+ if (r < 0)
+ ERROR("Could not parse address: %s\n", p);
+
+ return r;
+}
+
+int nw_config_write_address(nw_config* config,
+ const char* key, const void* value, const size_t length, void* data) {
+ const nw_address_t* address = (nw_address_t*)value;
+ int r;
+
+ // Format the address to string
+ char* p = nw_address_to_string(address);
+ if (!p)
+ return -errno;
+
+ // Store the value
+ r = nw_config_set(config, key, p);
+ if (r < 0)
+ goto ERROR;
+
+ // Success
+ r = 0;
+
+ERROR:
+ if (p)
+ free(p);
+
+ return r;
+}