#include #include #include #include #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; }; /* Create a new Uconfig pair. KEY and VALUE are copied to create the new * pair. */ static struct uconfig_pair_s *uconfig_pair_new(const char *key, const char *value) { struct uconfig_pair_s *pair = malloc(sizeof(struct uconfig_pair_s)); pair->key = strdup(key); pair->value = strdup(value); 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 char_is_blank(int c) { return c == ' ' || c == '\t' || c == '\n'; } /* Remove all the leading and trailing blank characters from STR. STR is * modified in-place. */ static char *trim(char *str) { int len = strlen(str); while ((len > 0) && char_is_blank(*str)) { str++; len--; } while ((len > 0) && char_is_blank(str[len - 1])) { str[len - 1] = '\0'; len--; } if (len == 0) { fprintf(stderr, "%s: warning: returning empty string\n", __func__); } return str; } static int uconfig_parse_line(struct uconfig_s *uconfig, const char *file, int line_number, char *line) { char *sep_ptr = strchr(line, '='); if (sep_ptr == NULL) { fprintf(stderr, "%s: %s:%d: no '=' character found\n", __func__, file, line_number); return -1; } *sep_ptr = '\0'; char *key = trim(line); char *value = trim(sep_ptr + 1); struct uconfig_pair_s *pair = uconfig_pair_new(key, value); 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); 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); }