1 // Copyright (2013) Jann Horn <jann@thejh.net>
2 // This code is licensed under the AGPLv3.
4 // Supports very simple ini files. Structure:
5 // - data is in lines, key=value
6 // - # or ; starts a comment line
7 // - lines without = are ignored, too
9 HEADER #include <string.h>
16 HEADER struct inifile_entry {
19 HEADER struct inifile_entry *next;
22 HEADER struct inifile {
23 HEADER struct inifile_entry *first;
26 // Parses an inifile. When you're done, you can free the whole thing
27 // (including all the entries and the strings) by freeing the pointer
28 // that this function returns.
29 PUBLIC_FN struct inifile *parse_inifile(char *f) {
30 int n_of_lines = count_char_occurences(f, '\n')+1;
31 size_t worst_case_size = strlen(f) +
32 n_of_lines*sizeof(struct inifile_entry) +
33 sizeof(struct inifile);
35 char *buf = malloc(worst_case_size);
36 if (buf == NULL) return NULL;
38 struct inifile *head = (void*)buf;
39 void *buf_ = (void*)(head+1);
41 struct inifile_entry **nextp = &head->first;
44 char *nl = strchr(f, '\n');
45 if (!nl) nl=f+strlen(f);
46 if (*f == '#' || *f == ';') goto next;
47 char *eqsign = strchr(f, '=');
49 if (eqsign > nl) goto next;
51 struct inifile_entry *e = buf_; buf_ = e+1;
52 *nextp = e; nextp = &e->next;
54 int keylen = eqsign-key;
55 char *value = eqsign+1;
56 int valuelen = nl-value;
57 e->key = buf_; buf_+=keylen+1;
58 memcpyn(e->key, key, keylen);
59 trim_end(e->key, " \r");
60 e->value = buf_; buf_+=valuelen+1;
61 memcpyn(e->value, value, valuelen);
62 trim_end(e->value, " \r");
74 PUBLIC_FN struct inifile *fslurp_inifile(int fd) {
75 char *f = slurp_fd(fd, NULL, 0);
76 if (f == NULL) return NULL;
77 struct inifile *r = parse_inifile(f);
84 PUBLIC_FN struct inifile *slurp_inifile(char *path) {
85 int fd = open(path, O_RDONLY);
86 if (fd == -1) return NULL;
87 struct inifile *r = fslurp_inifile(fd);
94 PUBLIC_FN char *inifile_lookup(struct inifile *inf, char *key) {
95 for (struct inifile_entry *e = inf->first; e; e=e->next) {
96 if (streq(e->key, key)) return e->value;