diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/uconfig.c | 142 |
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); +} |
