aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/uconfig.c142
1 files changed, 142 insertions, 0 deletions
diff --git a/src/uconfig.c b/src/uconfig.c
new file mode 100644
index 0000000..431f76a
--- /dev/null
+++ b/src/uconfig.c
@@ -0,0 +1,142 @@
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "uconfig.h"
+
+struct uconfig_pair_s {
+ char *key;
+ char *value;
+ struct uconfig_pair_s *next;
+};
+
+struct uconfig_s {
+ struct uconfig_pair_s *head;
+ struct uconfig_pair_s *tail;
+};
+
+static struct uconfig_pair_s *uconfig_pair_new(char *line, int sep_idx)
+{
+ assert(line[sep_idx] == '=');
+ line[sep_idx] = '\0';
+ struct uconfig_pair_s *pair = malloc(sizeof(struct uconfig_pair_s));
+ pair->key = strdup(line);
+ pair->value = strdup(line + sep_idx + 1);
+ pair->next = NULL;
+ return pair;
+}
+
+static void uconfig_add_tail(struct uconfig_s *uconfig,
+ struct uconfig_pair_s *pair)
+{
+ if (!uconfig->head) {
+ /* first pair in the config handle */
+ uconfig->head = pair;
+ uconfig->tail = pair;
+ }
+ else {
+ uconfig->tail->next = pair;
+ uconfig->tail = pair;
+ }
+}
+
+static int uconfig_parse_line(struct uconfig_s *uconfig,
+ const char *file,
+ int line_number,
+ char *line,
+ ssize_t line_len)
+{
+ /* Remove trailing newline, if any */
+ if (line[line_len - 1] == '\n') {
+ line[line_len - 1] = '\0';
+ line_len--;
+ }
+
+ /* Find index of '=' character in the line */
+ int sep_idx = 0;
+ while ((sep_idx < line_len) && (line[sep_idx] != '=')) {
+ sep_idx++;
+ }
+ if (sep_idx == line_len) {
+ fprintf(stderr,
+ "%s: %s:%d: no '=' character found\n",
+ __func__, file, line_number);
+ return -1;
+ }
+
+ struct uconfig_pair_s *pair = uconfig_pair_new(line, sep_idx);
+ uconfig_add_tail(uconfig, pair);
+ return 0;
+}
+
+struct uconfig_s *uconfig_new(const char*file)
+{
+ FILE *input = fopen(file, "r");
+ struct uconfig_s *uconfig = NULL;
+ ssize_t line_len;
+ size_t line_size = 128;
+ char *line = NULL;
+ int line_number = 1;
+ int rc;
+
+ if (input == NULL) {
+ fprintf(stderr, "%s: fopen: %s: ", __func__, file);
+ perror("");
+ goto err;
+ }
+
+ uconfig = calloc(1, sizeof(struct uconfig_s));
+ line = malloc(line_size);
+
+ while ((line_len = getline(&line, &line_size, input)) != -1) {
+ rc = uconfig_parse_line(uconfig, file, line_number, line, line_len);
+ if (rc == -1)
+ goto err;
+ line_number++;
+ }
+
+ if (ferror(input)) {
+ fprintf(stderr, "%s: getline: %s: ", __func__, file);
+ perror("");
+ goto err;
+ }
+
+ free(line);
+ fclose(input);
+ return uconfig;
+
+err:
+ if (input)
+ fclose(input);
+ if (line)
+ free(line);
+ if (uconfig)
+ uconfig_destroy(uconfig);
+ return NULL;
+}
+
+const char *uconfig_get(const struct uconfig_s *uconfig, const char *key)
+{
+ struct uconfig_pair_s *pair = uconfig->head;
+ while (pair) {
+ if (strcmp(pair->key, key) == 0)
+ return pair->value;
+ pair = pair->next;
+ }
+ return NULL;
+}
+
+static void uconfig_destroy_pairs(struct uconfig_pair_s *pair)
+{
+ if (pair->next)
+ uconfig_destroy_pairs(pair->next);
+ free(pair->key);
+ free(pair->value);
+ free(pair);
+}
+
+void uconfig_destroy(struct uconfig_s *uconfig)
+{
+ uconfig_destroy_pairs(uconfig->head);
+}